2

我目前正在对我的程序进行基准测试,看看我是否可以提高它的性能。目前我的程序将获取一个输入文件并运行一些算法将其拆分为多个文件。

将文件拆分为 3 部分大约需要 14 秒,其中-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 通常是瓶颈,但我想看看我是否可以提高我的程序的运行时性能。

干杯!

4

1 回答 1

1

按照 nh2 的建议,我决定将它们打包成ByteStrings256 字节的块,而不是BS.singleton对每个Word8实例都执行一次。

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

代替

cbs = CC.map BS.singleton

而且我能够显着减少运行时间和内存使用量,如下所示:

原始运行

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

新运行,与CL.take

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

这是一些严重的改进!我想对其进行更多优化,但这是另一个问题:)

于 2014-05-31T05:02:00.490 回答