f
大きな整数を返す関数aがあります。終わりに近づくと、プログラムはのすべての戻り値を合計する必要がありますf
。このコンピュータの物理メモリは、のすべての戻り値を保存するには制限が多すぎますf
。したがって、これをファイルバッファに入れる必要があります。TVarsは整数を処理できますか?のすべての戻り値をスローできる解決策はありf
ますか?また、別々のスレッドがそれを読み取ると同時にバッファリングすることができますか?
2 に答える
あなたがやりたいことの説明は少し曖昧なので、あなたが必要なものにたどり着くには、より多くの情報とより多くの質問が必要になるでしょう。
あなたの最初の質問:
TVarsは整数を処理できますか?
答えは「はい」です。には任意の値を格納できますが、ボックス化されてTVar
いない値は格納できません(ボックス化されていない値は、実装の一部を公開し、タイプに#記号が含まれるGHC拡張機能です)。
fのすべての戻り値をスローできる解決策はありますか?
「投げる」は「足し合わせる」という意味だと思いますか?TVar
その場合、 orMVar
または(シングルスレッドまたは本当に注意深い場合)のような可変変数で現在の合計を維持できますIOVar
。
「x+y」を格納すると、「x」に適用された「(+)」とレイジーサンクである「y」が格納されることに注意してください。可変変数に格納する前に、weak-head-normal-form(WHNF)への追加を強制する必要があります。
また、別々のスレッドがそれを読み取ると同時にバッファリングすることができますか?
この質問の「バッファ」とはどういう意味ですか?推測できません。
複数の同時スレッドによってアクセスされる可変変数に現在の合計を保持している場合は、を使用しMVar Integer
ます。
あなたの質問はそれほど明確ではありません。私が理解していることから、プログラムの実行中に関数fが返したすべての結果を保存する必要があり、そのような結果が多数あるため、それらの結果をファイルに保存したいと思います。計算されたらすぐに各結果を実際に保存するのは非効率的であるため、ある形式のバッファリングを実装する必要があります。
この場合、たとえば、無制限のブロッキングFIFOキューであるChanのようなものを使用できます。そして、あなたの懸念の1つに答えるために、この構造は、複数のスレッドからの同時アクセス用に特別に設計されました。
したがって、fを呼び出すメインプログラムを実行し、呼び出しごとに結果をChanに挿入することもできます。また、Chanから継続的に読み取り、結果をファイルに書き込む別のスレッドを生成します。
ここで、メインスレッド(fを呼び出すスレッド)のレートが、他のスレッドが結果をディスクに保存するレートよりもはるかに高い場合は、結果がChanに積み重なる元の問題に戻ります。ある時点でメモリ不足のままになります。この特定のケースでは、 BoundedChanのようなものを使用できます。これは、Chanに似ていますが、チャネルがいっぱいになると挿入時にブロックされます。このシナリオでは、メインスレッドは書き込みスレッドが結果をディスクに保存するのを時々待たなければならないかもしれませんが、fの多くの結果でメモリがいっぱいになることは決してないという保証があります。
これについては、実際に優れた抽象化を構築できます。関数fと値を格納する方法を指定すると、fと同じ結果を返す関数が得られる関数を想像できtraceable
ますが、副作用として、後で分析するために結果も格納されます。
traceable :: (a -> b) -> (b -> IO ()) -> (a -> IO b)
traceable f store = \x -> do
let result = f x
store result
return result
あなたの場合、プログラムは次のようになります。
f :: Int -> Int
f = ... -- implementation of f here
main = do
ch <- newChan
traceableF = traceable f (writeChan ch)
forkIO $ resultWriter ch
-- the main program which calls traceableF here ...
resultWriter :: Chan Int -> IO ()
resultWriter ch = do
f <- obtainFileHandler
forever $ do
result <- readChan
writeToFile f result
メインスレッドがスレッドがディスクへの書き込みを終了するのを待つように、ロジックを作成する必要がある場合もありますがresultWriter
、基本的にはそれだけです。
これがあなたの質問に答えることを願っています。