4

バイナリ ファイルを読み込んで、「バイナリ」パッケージを使用して遅延解析しようとしています。パッケージのドキュメントには、私のものと非常によく似たシナリオですべての入力を強制せずにこれを行う方法の例が示されています。

 example2 :: BL.ByteString -> [Trade]
 example2 input
  | BL.null input = []
  | otherwise =
    let (trade, rest, _) = runGetState getTrade input 0
    in trade : example2 rest

ただし、これは非推奨のrunGetState関数を使用しており、それ自体が関数を指していrunGetIncrementalます。

問題は、「ru​​nGetIncremental」関数が残りの入力を厳密なバイト文字列に強制するように見えるため、ファイル全体を強制的にメモリにロードすることです。実際、これを実行しようとすると、約 6GB のメモリ使用量が見られます。nowの実装でさえ、runGetStateに基づいているようで、runGetIncrementalを使用して厳密なバイト文字列を遅延文字列に再変換しchunkます。

チュートリアルで説明されている動作を取得できますか、またはこれは現在バイナリでサポートされていませんか? 後者の場合、これを行うための最良の方法は何ですか? コンジットを使用した経験は少しありますが、ここでどのように使用できるかは明確ではありません。

4

1 に答える 1

2

pipes-binaryと を使用してこれを行うことができますpipes-bytestring。これがあなたの利益のためのヘルパー関数です:

import Control.Monad (void)
import Data.Binary
import Pipes
import Pipes.Binary (decodeMany)
import Pipes.ByteString (fromHandle)
import qualified Pipes.Prelude as P
import System.IO

decodeHandle :: (Binary a) => Handle -> Producer a IO ()
decodeHandle handle = void $ decodeMany (fromHandle handle) >-> P.map snd

voidmap sndが存在するのは、decodeMany実際にはより多くの情報 (バイト オフセットや解析エラーなど) を返すためです。本当にその情報が必要な場合は、それらを削除してください。

を使用する方法の例を次に示しますdecodeHandle。簡単なスケルトンを使用して、Trade一緒に投げました。

data Trade = Trade

instance Binary Trade where
    get   = return Trade
    put _ = return ()

instance Show Trade where show _ = "Trade"

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    for (decodeHandle handle) $ \trade -> do
        lift $ print (trade :: Trade)
        -- do more with the parsed trade

デコードされた取引をループして処理するために使用forできます。または、必要に応じてパイプ構成を使用できます。

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    decodeHandle handle >-> P.print

これは怠惰で、実際に必要な数の取引のみをデコードします。したがってtake、デコーダーとプリンターの間に を挿入すると、要求された数の取引を処理するために必要なだけの入力のみが読み取られます。

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    for (decodeHandle handle >-> P.take 4) $ \trade -> do
        ... -- This will only process the first 4 trades

-- or using purely pipe composition:

main = withFile "inFile.txt" ReadMode $ \handle -> runEffect $
    decodeHandle handle >-> P.take 4 >-> P.print
于 2013-11-08T17:55:41.727 に答える