2011-09-22 11 views
7

ハスケルで大量のデータを読み取るのに[Char]を使用しないことはよく知られています。 1つはByteStringを使用してジョブを実行します。 これについての通常の説明は、Charが大きく、リストがオーバーヘッドを追加することです。[Char]ベースの入力がHaskellの[Char]ベースの出力よりもずっと遅いのはなぜですか?

しかし、これは出力に何の問題も生じないようです。最初のプログラムの出力を与えた場合

import Data.List 

sum' :: [Int] -> Int 
sum' = foldl' (+) 0 

main = interact $ show . sum' . map read . words 

は3.38秒かかります。たとえば

次のプログラム:1次ながら

main = interact $ const $ unwords $ map show $ replicate 500000 38000000 

は、私のコンピュータ上で実行するだけで131ミリ秒かかります入力として!

Stringを使用した入出力パフォーマンスのこのような不一致の理由は何ですか?

+1

私のクイックプロファイリングは、入力プログラムが出力プログラムよりも13倍多くのメモリを割り当てることを示しています。これは確かに格差に寄与する。 –

答えて

10

この問題はI/Oと必ずしも関係していないと思います。それどころか、IntReadインスタンスが非常に非効率的であることを示しています。

まず、レイジーリストを処理する次のプログラムを考えてみましょう。これは、(-O2でコンパイルされた)私のマシン上で4.1sを取りますlengthread機能を交換

main = print $ sum' $ map read $ words 
     $ unwords $ map show $ replicate 500000 38000000 

はダウン0.48sまでの時間をドロップします。

さらに
main = print $ sum' $ map length $ words 
     $ unwords $ map show $ replicate 500000 38000000 

、手書きでread機能を置き換えますバージョンは0.52秒で表示されます。

main = print $ sum' $ map myread $ words 
     $ unwords $ map show $ replicate 500000 38000000 

myread :: String -> Int 
myread = loop 0 
    where 
    loop n [] = n 
    loop n (d:ds) = let d' = fromEnum d - fromEnum '0' :: Int 
         n' = 10 * n + d' 
        in loop n' ds 

私の推測理由はreadです非常に効率が悪いのは、モジュールの実装でText.ParserCombinators.ReadPモジュールが使用されていることです。単一の整数を読み取る単純なケースでは、これが最速の選択ではない可能性があります。

+1

ああ、 'String'を使わない主な理由は' String'とは関係ありません。これはとても不公平です。 – Rotsor

+2

「読み込み」は、エラーチェック、空白スキップ、負の数値、16進数、8進数、さらには指数関数表記のようないくつかのことを行います。 –

+0

'read'のためにどのように8進数を書いていますか?プレフィックスに「0」という数字がないことを願っています。 – Rotsor

関連する問題