gpt4 book ai didi

haskell - 如何读取大的csv文件?

转载 作者:行者123 更新时间:2023-12-02 21:29:59 25 4
gpt4 key购买 nike

我尝试通过 haskell 读取一个大的 csv 文件,并按每列生成字数。

该文件超过 4M 行。

所以我选择读取一个 block 并每次获取字数(一个 block 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)

最佳答案

首先,我提出一些建议。

  1. 列表速度并不快。好吧,好吧,缺点是恒定的时间,但总的来说,列表并不快。您正在使用列表。 (对于两端的cons'ing和消费来说,Data.Sequence会更快)

  2. 字符串速度很慢。字符串很慢,因为它们是 [Char](Char 列表)。您当前使用的库是用字符串列表编写的。通常,字符链接列表的链接列表并不是您想要进行文本处理的。这不是布埃诺。以后使用 Text(呃,文本)或 ByteString(字节)代替 String,除非它很小并且对性能不敏感。

  3. 您使用的库只是惰性的,而不是流式的。您必须处理将流行为叠加到惰性语义上以获得恒定的内存使用。流式库解决了增量处理数据和限制内存使用的问题。我建议学习 Pipes 或 Conduit 来解决此类一般问题。一些针对特定问题的库还将提供可用于流式传输的 iteratee API。 Iteratee API 可以直接使用,也可以连接到 Pipes/Conduit/等。

我认为您使用的库不是一个好主意。

我建议您使用以下库之一:

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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com