Performance 提高文件操作的性能

Performance 提高文件操作的性能,performance,haskell,functional-programming,bytestring,Performance,Haskell,Functional Programming,Bytestring,我有一个包含数字矩阵的文件,如下所示: 0 10 24 10 13 4 101 ... 6 0 52 10 4 5 0 4 ... 3 4 0 86 29 20 77 294 ... 4 1 1 0 78 100 83 199 ... 5 4 9 10 0 58 8 19 ... 6 58 60 13 68 0 148 41 ... . . . . . . 我试图做的是对每一行求和,并将每一行的和输出到一个新文件中(每一行的和在一个新行上) 我曾尝试使用ByteStrings在Ha

我有一个包含数字矩阵的文件,如下所示:

0 10 24 10 13 4 101 ...
6 0 52 10 4 5 0 4 ...
3 4 0 86 29 20 77 294 ...
4 1 1 0 78 100 83 199 ...
5 4 9 10 0 58 8 19 ...
6 58 60 13 68 0 148 41 ...
. .
.   .
.     .
我试图做的是对每一行求和,并将每一行的和输出到一个新文件中(每一行的和在一个新行上)

我曾尝试使用ByteStrings在Haskell中实现,但性能比python实现慢3倍。以下是Haskell实现:

import qualified Data.ByteString.Char8 as B

-- This function is for summing a row
sumrows r = foldr (\x y -> (maybe 0 (*1) $ fst <$> (B.readInt x)) + y) 0 (B.split ' ' r)

-- This function is for mapping the sumrows function to each line
sumfile f = map (\x -> (show x) ++ "\n") (map sumrows (B.split '\n' f)) 

main = do
  contents <- B.readFile "telematrix"
  -- I get the sum of each line, and then pack up all the results so that it can be written
  B.writeFile "teleDensity" $ (B.pack . unwords) (sumfile contents)
  print "complete"
对于相同的25MB文件,这大约需要5秒钟


有没有关于如何增加Haskell实现的建议?

乍一看,我敢打赌您的第一个瓶颈是
++
sumfile
中的字符串上,这就是每次对左操作数进行解构并重建它。您可以将
unwords
函数调用替换为
unlines
,而不是在末尾追加
“\n”
,这正是您想要的。这会给你带来一个小小的提速

更细微的挑剔是,
函数中的
(*1)
可能是不需要的。使用
id
效率会更高,因为
(*1)
浪费了乘法运算,但这不超过几个处理器周期


最后,我要问你为什么要使用
ByteString
ByteString
将字符串数据高效地存储为数组,就像更命令式语言中的传统字符串一样。然而,这里要做的是拆分字符串并迭代元素,这是链表适合的操作。我真诚地建议在这种情况下使用传统的
[Char]
类型。这个
B.split
调用可能会毁了你,因为它必须把整行代码复制到split表单的单独数组中,而用于字符链接列表的
words
函数只是在几个点上分离链接结构。

问题似乎在于我使用runhaskell编译和运行程序,而不是使用ghc然后运行程序。通过先编译然后运行,我在Haskell中将性能提高到1秒。性能差的主要原因是我使用的是runhaskell,而不是先编译然后运行程序。所以我从:

runhaskell program.hs


你能链接到这个文件吗?在我的电脑上,你的Haskell程序的运行速度是Python程序的4倍,它有一个随机的1000 x 1000矩阵(13 Mb)。我想我可能已经知道为什么它这么慢了。我使用Runaskell而不是用GHC编译它,然后运行它。<代码> GHC-O2/<代码>执行什么?@ abDNo3如果它确实是由<代码> Runaskele<代码>引起的,请考虑将它作为自己的答案添加(稍后接受它),这样问题就被标记为已解析。您应该使用<代码> Fordl(+)0
来求整数和,而不是
foldr(+)0
(您已经手动将其与另一个循环融合,但我希望您明白我的意思)。
B.split
不复制数据,它返回切片
ByteString
绝对比OP任务的列表快得多。另外,
sumfile
中的
++
是每行的一次性小O(n)成本,不会对总运行时间产生太大影响。我很确定使用
ByteString
B.split
是可以的,实际上有助于提高性能。该库不复制阵列,而是创建指向原始数据段的拼接。特别是关于says:>的文档,对于这个库中的所有拆分函数,这个函数不复制子字符串,它只是构造新的bytestring,这些bytestring是原始函数的切片。
runhaskell program.hs
ghc program.hs

./program