【发布时间】:2015-10-05 13:17:14
【问题描述】:
我想在 Haskell 中重新实现我的一些 ASCII 解析器,因为我认为我可以获得一些速度。但是,即使是简单的“grep and count”也比草率的 Python 实现要慢得多。
谁能解释一下为什么以及如何正确地做到这一点?
所以任务是,计算以字符串“foo”开头的行数。
我非常基本的 Python 实现:
with open("foo.txt", 'r') as f:
print len([line for line in f.readlines() if line.startswith('foo')])
还有 Haskell 版本:
import System.IO
import Data.List
countFoos :: String -> Int
countFoos str = length $ filter (isPrefixOf "foo") (lines str)
main = do
contents <- readFile "foo.txt"
putStr (show $ countFoos contents)
使用time 在大约 600MB 的文件上运行 17001895 行表明,Python 实现几乎比 Haskell 快 4 倍(在我的 MacBook Pro Retina 2015 和 PCIe SSD 上运行) :
> $ time ./FooCounter
1770./FooCounter 20.92s user 0.62s system 98% cpu 21.858 total
> $ time python foo_counter.py
1770
python foo_counter.py 5.19s user 1.01s system 97% cpu 6.332 total
与 unix 命令行工具相比:
> $ time grep -c foo foo.txt
1770
grep -c foo foo.txt 4.87s user 0.10s system 99% cpu 4.972 total
> $ time fgrep -c foo foo.txt
1770
fgrep -c foo foo.txt 6.21s user 0.10s system 99% cpu 6.319 total
> $ time egrep -c foo foo.txt
1770
egrep -c foo foo.txt 6.21s user 0.11s system 99% cpu 6.317 total
有什么想法吗?
更新:
使用 András Kovács 的实现 (ByteString),我不到半秒就搞定了!
> $ time ./FooCounter
1770
./EvtReader 0.47s user 0.48s system 97% cpu 0.964 total
【问题讨论】:
-
如果没有,请用-O2编译。
-
不要使用
String。使用ByteString或(更有可能)Text。String类型非常灵活,但对几乎所有事情都非常低效。 -
@AndrásKovács 我忘了提,我确实用 -O2 编译过它。实际上这并没有什么区别 :-\ 无论如何:köszi
-
@MathematicalOrchid 但
readFile有readFile :: FilePath -> IO String。我应该如何强制使用ByteString或Text? -
@septi 看看
Data.Text.IO。您会发现另一个readFile函数返回Text。
标签: haskell file-io text-parsing