我试图通过 haskell 读取一个大的 csv 文件,并按每列生成字数。
这在文件中超过 4M 行。
所以我选择读取一个块并每次获取字数(5k 行一个块)。
然后把它加在一起。
当我用 12000 行和 120000 行测试函数时,时间几乎呈线性增加。
但是当读取180000行时,运行时间超过了四倍。
我觉得是内存不够用,换磁盘让功能慢很多。
我已经将我的代码编写为 map/reduce 样式,但是如何使 haskell 不将所有数据保存在内存中?
打击是我的代码和分析结果。
import Data.Ord
import Text.CSV.Lazy.String
import Data.List
import System.IO
import Data.Function (on)
import System.Environment
splitLength = 5000
mySplit' [] = []
mySplit' xs = [x] ++ mySplit' t
where
x = take splitLength xs
t = drop splitLength xs
getBlockCount::Ord a => [[a]] -> [[(a,Int)]]
getBlockCount t = map
(map (\x -> ((head x),length x))) $
map group $ map sort $ transpose t
foldData::Ord a=> [(a,Int)]->[(a,Int)]->[(a,Int)]
foldData lxs rxs = map combind wlist
where
wlist = groupBy ((==) `on` fst) $ sortBy (comparing fst) $ lxs ++ rxs
combind xs
| 1==(length xs) = head xs
| 2 ==(length xs) = (((fst . head) xs ), ((snd . head) xs)+((snd . last) xs))
loadTestData datalen = do
testFile <- readFile "data/test_csv"
let cfile = fromCSVTable $ csvTable $ parseCSV testFile
let column = head cfile
let body = take datalen $ tail cfile
let countData = foldl1' (zipWith foldData) $ map getBlockCount $ mySplit' body
let output = zip column $ map ( reverse . sortBy (comparing snd) ) countData
appendFile "testdata" $ foldl1 (\x y -> x ++"\n"++y)$ map show $tail output
main = do
s<-getArgs
loadTestData $ read $ last s
分析结果
loadData +RTS -p -RTS 12000
total time = 1.02 secs (1025 ticks @ 1000 us, 1 processor)
total alloc = 991,266,560 bytes (excludes profiling overheads)
loadData +RTS -p -RTS 120000
total time = 17.28 secs (17284 ticks @ 1000 us, 1 processor)
total alloc = 9,202,259,064 bytes (excludes profiling overheads)
loadData +RTS -p -RTS 180000
total time = 85.06 secs (85059 ticks @ 1000 us, 1 processor)
total alloc = 13,760,818,848 bytes (excludes profiling overheads)
最佳答案
所以首先,提出一些建议。
我认为您使用的库不是一个好主意。
我建议您使用以下库之一:
http://hackage.haskell.org/package/pipes-csv(基于管道)
https://hackage.haskell.org/package/cassava-0.4.2.0/docs/Data-Csv-Streaming.html(通用 CSV 库,不基于特定的流媒体库)
https://hackage.haskell.org/package/csv-conduit(基于导管)
这些应该为您提供良好的性能和恒定的内存使用模数,无论您可能累积什么。
关于haskell - 如何读取大的csv文件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26706997/