Basic I/O performance in Haskell

后端 未结 3 765
别跟我提以往
别跟我提以往 2021-01-03 08:31

Another microbenchmark: Why is this \"loop\" (compiled with ghc -O2 -fllvm, 7.4.1, Linux 64bit 3.2 kernel, redirected to /dev/null)



        
3条回答
  •  天命终不由人
    2021-01-03 08:41

    The standard Haskell way to hand giant bytestrings over to the operating system is to use a builder monoid.

    import Data.ByteString.Lazy.Builder  -- requires bytestring-0.10.x
    import Data.ByteString.Lazy.Builder.ASCII -- omit for bytestring-0.10.2.x
    import Data.Monoid
    import System.IO
    
    main = hPutBuilder stdout $ build  [0..100000000::Int]
    
    build = foldr add_line mempty
       where add_line n b = intDec n <> charUtf8 '\n' <> b
    

    which gives me:

     $ time ./printbuilder >> /dev/null
     real   0m7.032s
     user   0m6.603s
     sys    0m0.398s
    

    in contrast to Haskell approach you used

    $ time ./print >> /dev/null
    real    1m0.143s
    user    0m58.349s
    sys 0m1.032s
    

    That is, it's child's play to do nine times better than mapM_ print, contra Daniel Fischer's suprising defeatism. Everything you need to know is here: http://hackage.haskell.org/packages/archive/bytestring/0.10.2.0/doc/html/Data-ByteString-Builder.html I won't compare it with your C since my results were much slower than Daniel's and n.m. so I figure something was going wrong.

    Edit: Made the imports consistent with all versions of bytestring-0.10.x It occurred to me the following might be clearer -- the Builder equivalent of unlines . map show:

    main = hPutBuilder stdout $ unlines_ $ map intDec [0..100000000::Int]
     where unlines_ = mconcat . map (<> charUtf8 '\n')
    

提交回复
热议问题