使用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