4

IO をアトミックに実行する必要があると思われる次の関数を作成しました (他のすべての人が同じを使用している限りMVar)。

atomicIO :: MVar () -> IO a -> IO a
atomicIO mvar io =
  do
    takeMVar mvar
    result <- io
    putMVar mvar ()
    return result

また、私が理解していることから、Haskell IO の一部は遅延IORefしているため (例: s)、このセクションで実際にアクションを実行する必要はありません。実行する必要があるタスクをリストする「サンク」(正しい言葉ですか?) を返すだけです。

アイデアは、クリティカル セクション (つまり、シングル スレッド部分) は非常に高速であるべきだということです。

しかし、私が s に書き込んでいてIORef、Haskell に結果の計算をすぐに開始させたいとしましょう。しかし、前に言ったように、ロックを保持しているときにクリティカル セクションでロックされたくありませんMVar

だから私はこれを行うことを考えました:

    result <- io `par` io

またはこれ

    return result `par` result

またはこれ

    result `par` return result

しかし、これでうまくいくかどうかはわかりません。これらのいずれかが正しいアプローチですか、それとも別の方法がありますか? (後者の 2 つはIO ()アクション()です。並行して評価しても実際には何の効果もないと考えているからです)。

4

2 に答える 2

4

あなたが持っているところ

writeIORef myRef newValue

それを次のように置き換えます

newValue `par` writeIORef myRef newValue

それはバックグラウンドで評価するためにスレッドをスパークさせnewValueます...

... WHNFに対してのみ評価されることに注意してください(基本的に、データ構造の最初のレベルのみが評価されます)。したがって、Intは完全に評価されますが、評価されStringません。Maybe a値は、に完全に評価されるかNothing、部分的に評価されJust _ます。

したがって、より複雑なデータ構造を使用している場合はforce、deepseqパッケージのControl.DeepSeqを使用する必要があります。これにより、値が完全に評価されます。

force newValue `par` writeIORef myRef newValue

を使用したい場合は、直接modifyIORef再利用できるとは思いませんが、同様の関数を定義することはできますとにかく定義されいます) :modifyIORefmodifyIORefreadIORefwriteIORef

modifyIORefInParallel :: NFData a => IORef a -> (a -> a) -> IO ()
modifyIORefInParallel ref f
   = do old <- readIORef ref
        let new = f old
        force new `par` writeIORef ref new

(最後の行がforce (f old) `par` writeIORef ref (f old)機能しない場合は、機能しないことに注意してください。並列に強制された値は、参照に格納された値ではありません。)

NFData a制限は使用によるものforceです。)

于 2012-04-16T08:25:32.890 に答える
1

高速なクリティカル セクションを取得する唯一の方法は、高速な IO アクションに限定することです。内部で厳密な評価を強制しようとしてatomicIOも速度が上がるとは思いません。さらに、atomicIOそれ自体が厳密に評価されない場合があることに注意してください。その場合、内部の厳密な評価atomicIOは何の効果もありません。

いずれにせよ、並列計算を開始しようとしていないため、厳密な評価seqの代わりに使用できます。par

于 2012-04-16T08:13:49.563 に答える