同じコンジット値を使用して複数のアクションを実行しても安全ですか? 何かのようなもの
do
let sink = sinkSocket sock
something $$ sink
somethingElse $$ sink
コンジットの初期のバージョンでは、これを安全でなくするいくつかの汚いハックがあったことを思い出します。現在の状況は?
sinkSocket
(ソケットを閉じないことに注意してください。)
その使用法は完全に安全です。古いバージョンの問題は、再開可能なコンポーネントと再開不可能なコンポーネントの間の境界線があいまいになることに関係していました。最近のバージョン (0.4 以降だと思います) では、両者の境界線は非常に明確です。
「使用された」シンクのセマンティクスが変わらないという意味で、シンクを再利用しても安全かもしれません。しかし、別の脅威に注意する必要があります: スペース リークです。
この状況は遅延リストに似ています。一定のスペースで巨大なリストを遅延して消費できますが、リストを 2 回処理するとメモリに保持されます。同じことが再帰的なモナド式でも発生する可能性があります。一度使用するとサイズは一定ですが、再利用すると計算の構造がメモリに保持されるため、スペース リークが発生します。
次に例を示します。
import Data.Conduit
import Data.Conduit.List
import Control.Monad.Trans.Class (lift)
consumeN 0 _ = return ()
consumeN n m = do
await >>= (lift . m)
consumeN (n-1) m
main = do
let sink = consumeN 1000000 (\i -> putStrLn ("Got one: " ++ show i))
sourceList [1..9000000::Int] $$ sink
sourceList [1..22000000::Int] $$ sink
このプログラムは私のマシンで約 150M の RAM を使用しますが、最後の行を削除するかsink
、両方の場所で の定義を繰り返すと、一定のスペース使用量が得られます。
これは不自然な例 (これは私の頭に浮かんだ最初の例でした) であり、これはほとんどのシンクで発生する可能性が非常に低いことに同意します。たとえば、これはあなたのsinkSocket
. (なぜこれが不自然なのか: シンクの制御構造は、取得する値に依存しないためです。また、それがリークする可能性がある理由でもあります。) しかし、たとえば、ソースの場合、これははるかに一般的です。(多くの一般的な Source はこの動作を示します。sourceList
実際にはソースリストをメモリに保持するため、これは明らかな例です。しかし、enumFromTo
メモリに保持するデータはなく、モナドの構造だけで、違いはありません。計算します。)
ですから、全体として、これを認識することが重要だと思います。