Я пытаюсь прочитать большой файл csv по 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)
Вам необходимо использовать поточную библиотеку, например 'csv-conduit' или' pipes-csv' – ErikR