2014-05-25 132 views
2

我目前正在對我的程序進行基準測試,以查看我是否可以提高其性能。目前我的程序會接收一個輸入文件並運行一些算法將其分成多個文件。優化管道管道

將文件拆分爲3部分大約需要14s,對於庫和可執行文件都使用-O2編譯標誌。

ghc-options:   -Wall -fno-warn-orphans -O2 -auto-all 

看起來它會耗費其時間大約60%的sinkFile,我想知道是否有什麼我可以做,以改善下面的代碼。

-- | Get the sink file, a list of FilePaths and the share number of the file to output to. 
idxSinkFile :: MonadResource m 
      => [FilePath] 
      -> Int 
      -> Consumer [Word8] m() 
idxSinkFile outFileNames shareNumber = 
    let ccm = CC.concatMap $ flip atMay shareNumber 
     cbs = CC.map BS.singleton 
     sf = sinkFile (outFileNames !! shareNumber) 
    in ccm =$= cbs =$= sf 

-- | Generate a sink which will take a list of bytes and write each byte to its corresponding file share 
sinkMultiFiles :: MonadResource m 
       => [FilePath] 
       -> [Int] 
       -> Sink [Word8] m() 
sinkMultiFiles outFileNames xs = 
    let len = [0..length xs - 1] 
    in getZipSink $ otraverse_ (ZipSink . idxSinkFile outFileNames) len 

這裏是GHC的分析的輸出:

                        individual  inherited 
COST CENTRE        MODULE         no.  entries %time %alloc %time %alloc 

    splitFile.sink      HaskSplit.Conduit.Split    289   1 0.0 0.0 66.8 74.2 
     sinkMultiFiles      HaskSplit.Conduit.Split    290   1 27.4 33.2 66.8 74.2 
     idxSinkFile      HaskSplit.Conduit.Split    303   3 7.9 11.3 39.4 41.0 
     idxSinkFile.ccm     HaskSplit.Conduit.Split    319   3 3.1 3.6  3.1 3.6 
     idxSinkFile.cbs     HaskSplit.Conduit.Split    317   3 3.5 4.2  3.5 4.2 
     idxSinkFile.sf     HaskSplit.Conduit.Split    307   3 24.9 21.9 24.9 21.9 
     sinkMultiFiles.len    HaskSplit.Conduit.Split    291   1 0.0 0.0  0.0 0.0 

這都說明sinkFile採取了大量的時間。 (我已經基準列表訪問等,如果你想知道,他們有0%的處理)

雖然我理解像這樣的小程序IO往往是瓶頸,我想看看我是否可以提高我的程序的運行時性能。

乾杯!

+0

這可能是更多的信息,重新編譯'管道'和'conduit-extra'以'-auto-all'以及更詳細的地方看時間正在耗費。 –

+0

@MichaelSnoyman,嗯,我更希望這是我做得不對的事情。我會盡量深入挖掘。從過去的經驗來看,你有沒有一個「sinkFile」速度的粗略例子? –

+0

我不知道這是否與你的程序有關,但一些Web服務器像方法/ warp使用blaze-builder來構建可以有效輸出的ByteStrings – yokto

回答

1

遵循nh2的建議,我決定將ByteStrings打包爲256字節塊,而不是在每個Word8實例上執行BS.singleton

cbs = CL.sequence (CL.take 256) =$= CC.map BS.pack 

代替

​​

,我能夠減少運行時間和內存使用情況非常顯著,如下面所示:

原始運行

total time =  194.37 secs (194367 ticks @ 1000 us, 1 processor) 
total alloc = 102,021,859,892 bytes (excludes profiling overheads) 

New來看,隨着CL.take

total time =  35.88 secs (35879 ticks @ 1000 us, 1 processor) 
total alloc = 21,970,152,800 bytes (excludes profiling overheads) 

這是一些嚴重的改進!我想更多地優化它,但這是另一個問題:)