【问题标题】:How to speed Haskell IO with buffering?如何通过缓冲加速 Haskell IO?
【发布时间】:2015-01-26 07:15:11
【问题描述】:

我在“Real World Haskell”(第 7 章,第 189 页)中阅读了有关 IO 缓冲的内容,并尝试测试不同的缓冲大小如何影响性能。

import System.IO
import Data.Time.Clock
import Data.Char(toUpper)

main :: IO ()
main = do
  hInp <- openFile "bigFile.txt" ReadMode
  let bufferSize = truncate $ 2**10
  hSetBuffering hInp (BlockBuffering (Just bufferSize))
  bufferMode <- hGetBuffering hInp
  putStrLn $ "Current buffering mode: " ++ (show bufferMode)

  startTime <- getCurrentTime
  inp <- hGetContents hInp
  writeFile "processed.txt" (map toUpper inp)
  hClose hInp
  finishTime <- getCurrentTime
  print $ diffUTCTime finishTime startTime
  return ()

然后我创建了一个“bigFile.txt”

-rw-rw-r-- 1 user user 96M янв.  26 09:49 bigFile.txt

并针对这个文件运行我的程序,使用不同的缓冲区大小:

Current buffering mode: BlockBuffering (Just 32)
9.744967s   

Current buffering mode: BlockBuffering (Just 1024)
9.667924s                                      

Current buffering mode: BlockBuffering (Just 1048576)
9.494807s    

Current buffering mode: BlockBuffering (Just 1073741824)
9.792453s   

但是程序运行时间几乎是一样的。这是正常的,还是我做错了什么?

【问题讨论】:

    标签: performance haskell io buffering


    【解决方案1】:

    在现代操作系统上,缓冲区大小可能对线性读取文件几乎没有影响,因为 1) 内核执行预读和 2) 如果您已经读过文件,该文件可能已经在页面缓存中最近的文件。

    这是一个测量缓冲对写入的影响的程序。典型结果是:

    $ ./mkbigfile 32      -- 12.864733s
    $ ./mkbigfile 64      --  9.668272s
    $ ./mkbigfile 128     --  6.993664s
    $ ./mkbigfile 512     --  4.130989s
    $ ./mkbigfile 1024    --  3.536652s
    $ ./mkbigfile 16384   --  3.055403s
    $ ./mkbigfile 1000000 --  3.004879s
    

    来源:

    {-# LANGUAGE OverloadedStrings #-}
    
    import qualified Data.ByteString as BS
    import Data.ByteString (ByteString)
    import Control.Monad
    import System.IO
    import System.Environment
    import Data.Time.Clock
    
    main = do
      (arg:_) <- getArgs
      let size = read arg
      let bs = "abcdefghijklmnopqrstuvwxyz"
          n = 96000000 `div` (length bs)
      h <- openFile "bigFile.txt" WriteMode
      hSetBuffering h (BlockBuffering (Just size))
      startTime <- getCurrentTime
      replicateM_ n $ hPutStrLn h bs
      hClose h
      finishTime <- getCurrentTime
      print $ diffUTCTime finishTime startTime
      return ()
    

    【讨论】:

    • 那么为什么 OP 在他的程序中没有看到这种差异呢?
    • OP 的程序在读取句柄上设置缓冲,而不是在写入句柄上。
    • 即使内核有缓冲的东西,难道你还不需要系统调用来读取它吗?
    • 当然,但关键是为读取添加另一个级别的缓冲(这是 hSetBuffering 控制的)并不一定会加快速度。
    猜你喜欢
    • 1970-01-01
    • 2014-09-12
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 2012-07-08
    • 1970-01-01
    • 2017-10-17
    相关资源
    最近更新 更多