我想在
Haskell中重新实现一些我的ASCII解析器,因为我以为我可以获得一些速度.然而,即使一个简单的“grep和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)
运行时间在一个〜600MB的文件与17001895行显示,Python实现几乎比Haskell一个快四倍(运行在我的MacBook Pro Retina 2015与PCIe SSD):
与unix命令行工具相比:
有任何想法吗?
更新:
使用AndrásKovács的实现(ByteString),我得到了半秒钟!
- > $time ./FooCounter
- 1770
- ./EvtReader 0.47s user 0.48s system 97% cpu 0.964 total
解决方法
我对以下解决方案进行了基准测试:
- {-# LANGUAGE OverloadedStrings #-}
- import qualified Data.ByteString.Char8 as B
- main =
- print . length . filter (B.isPrefixOf "foo") . B.lines =<< B.readFile "test.txt"
text.txt是一个具有800万行的170 MB文件,一半的行以“foo”开头.我编译了GHC 7.10和-O2 -fllvm.
ByteString版本的运行时间为0.27秒,而原始版本的运行时间为5.16秒.
但是,严格的ByteString版本使用170 MB内存加载完整的文件.将导入更改为Data.ByteString.Lazy.Char8我有0.39秒运行时和1 MB内存使用.