1

STM パッケージを使用して並列マルチコア ブランチ アンド バウンド アルゴリズムを実装した課題のレポートを書いているところですが、直面した問題がありました。

STM を使用する実装は、STM の「アトミック」とコンカレントの「forkIO」の両方を使用するため、明らかに IO モナドにありますが、決定論的です。共有メモリ変数の使用にもかかわらず、関数の最終結果は常に同じ入力に対して同じになります。

私の質問は、「unsafePerformIO」以外に、IO から抜け出すためのオプションは何ですか? 複数のコアを使用すると、決定論に対して同じ保証がない他の並行コードに影響を与える可能性があるため、IOモナドからそれを取得しようとする必要があります。

Par モナド パッケージのことは聞いたことがありますが (使用したことはありません)、STM は IO モナドに存在し、スレッド セーフなグローバル変数を取得するために、STM に代わる唯一の方法は MVars (私が知っていること) です。 IO モナドにも存在します。

4

2 に答える 2

6

STM で unsafePerformIO を使用しないでください。STM には内部で副作用があり、unsafePerformIO を使用するとこれらの副作用が隠され、コードが見かけ上不純になり、リファクタリングが困難または危険になります。並列パッケージが役に立つかどうか、もっと試してみてください。

安全でない STM 操作が安全でない例の 1 つは、「純粋な」STM 操作を別の操作の中にネストして (おそらく高レベルのライブラリによって) 使用することになる場合です。たとえば、次のコード<loop>は、ネストされた STM 操作のためにループ ( で終了) します。古いバージョンの GHC がクラッシュしたことを思い出しますが、現在 GHC 7.0.1 でその動作を再現できないようです。

import Control.Concurrent
import Control.Concurrent.STM
import System.IO.Unsafe
import GHC.Conc.Sync

main = newTVarIO 5 >>= runComputation >>= print

runComputation :: TVar Int -> IO Int
runComputation tv = atomically $ do
        let y = getFiveUnsafe tv + 1
        writeTVar tv y
        return y

getFiveUnsafe tv = unsafePerformIO . atomically $ do
        x <- readTVar tv
        writeTVar tv (x + 5)
        return x

(他の人が説得力のある例を編集して追加することを歓迎します - 私はより良い例が存在すると信じています)

于 2011-10-14T15:59:53.617 に答える
0

STM関連する関数は使用できませんが、使用unsafePerformIOできforkIO、新しいスレッドをatomically安全に呼び出すことができます。次のようなことができます。

purifiedAlgorithm = unsafePerformIO $ do
  rr <- newEmptyMVar
  forkIO $ concurrentAlgorithm >> putMVar rr
  takeMVar rr
于 2016-08-25T06:30:29.530 に答える