我想重新用Haskell实现一些ASCII解析器,因为我认为这样可以提高速度。然而,即使是简单的“grep和计数”,也比粗糙的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)
在我的MacBook Pro Retina 2015上(使用PCIe SSD),对于一个大小约为600MB,包含17001895行的文件,同时使用time
命令运行,结果显示Python实现比Haskell实现快了近4倍。
> $ 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
String
。请改用ByteString
或者(更可能的选择)Text
。String
类型很灵活,但几乎对任何操作都非常低效。 - MathematicalOrchidreadFile
的类型签名是readFile :: FilePath -> IO String
,我该如何强制使用ByteString
或Text
? - tamasgalData.Text.IO
中看一下。你会发现另一个返回Text
的readFile
函数。 - MathematicalOrchid