使用String
的I/O在Haskell中已知不及速度快。从句柄中读取的字节通常必须转换为Unicode代码点,然后从这些字符串构建链接列表。这导致了很多分配的很多工作。在这种情况下,转换为代码点会更简单一些,因为您将stdin设置为二进制模式,但构建链接的字符列表仍然需要很长时间。
另一个小的因素是您的行数使用Integer
,但这很小,只在I/O达到速度时起作用。
如果您需要快速I/O,则必须使用更适合该类型的类型。一种可能性是使用ByteString
,例如
import Data.List
import qualified Data.ByteString.Lazy.Char8 as C
main = do
txt <- C.getContents
putStrLn $ (\(w,l)->"line:"++(show l)++"\nwords:"++(show w)++"\n"). foldl' (\(w,l) r-> w `seq` l `seq` (w+C.length r ,succ l)) (0,0) . C.lines $ txt
确实对我的盒子在0.12S一个94MB文件的作业(WC -l -c需要0.06S),而原来使用String
了4.4s。它可以进一步优化,
{-# LANGUAGE BangPatterns #-}
import Data.List
import qualified Data.ByteString.Lazy.Char8 as C
main = do
txt <- C.getContents
putStrLn $ (\(w,l)->"line:"++(show l)++"\nwords:"++(show w)++"\n"). loop 0 0 . C.lines $ txt
loop :: Int -> Int -> [C.ByteString] -> (Int,Int)
loop !w !l (ln:lns) = loop (w + fromIntegral (C.length ln)) (l+1) lns
loop w l _ = (w,l)
只需要0.08s,这是不够体面我停最佳那里(为String
版本类似的变化所带来的时间缩短到3.6s为)。
你用-O2编译过吗? – 2012-04-02 14:34:56
是的,-O2实际上只是加速大约0.xx秒 – vzex 2012-04-02 14:41:42
尝试使用ByteString:http://stackoverflow.com/questions/9746352/parsing-large-log-files-in-haskell – 2012-04-02 14:58:23