【问题标题】:Using the Par monad with STM and Deterministic IO将 Par monad 与 STM 和确定性 IO 一起使用
【发布时间】:2011-10-14 15:34:17
【问题描述】:

我正在为一项作业编写报告,其中我使用 STM 包实现了并发多核分支定界算法,但遇到了一个问题。

使用 STM 的实现显然在 IO monad 中,因为它同时使用 STM 的“原子”和 Concurrent 的“forkIO”,但它是确定性的。尽管使用了共享内存变量,对于相同的输入,函数的最终结果总是相同的。

我的问题是,在退出 IO 时,除了“unsafePerformIO”之外,我还有哪些选择?我是否应该尝试将其从 IO monad 中取出,因为使用多个内核可能会影响其他没有相同确定性保证的并发代码。

我听说过 Par monad 包(虽然没有使用它),但是 IO monad 中存在 STM,为了获得线程安全的全局变量,我唯一可以替代 STM 的方法是 MVars(我知道),也存在于 IO monad 中。

【问题讨论】:

  • Par monad 中的线程安全全局变量是IVars

标签: haskell concurrency monads parallel-processing stm


【解决方案1】:

请不要将 unsafePerformIO 与 STM 一起使用。 STM 在幕后有副作用,使用 unsafePerformIO 隐藏了这些副作用,使您的代码看似不纯,因此难以或危险重构。更加努力地看看并行包是否会对您有所帮助。

不安全的 STM 操作不安全的一个例子是,当您最终使用嵌套在另一个(可能是更高级别的库)内部的“纯”STM 操作时。例如,由于嵌套的 STM 操作,下面的代码循环(以<loop> 终止)。我记得较旧的 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

(我欢迎其他人编辑和添加更有说服力的示例 - 我相信存在更好的示例)

【讨论】:

  • 感谢您的建议。我不需要从 IO monad 中删除我的函数,这只是我的一个宠物好奇心,如果我(呵呵..)有时间我会怎么做。我主要是问,因为我知道这是可能的,因为函数是纯的。唯一的问题是是否存在提供所需功能的库。编辑:假设函数是纯的。
【解决方案2】:

STM及其相关函数不能从unsafePerformIO使用,但forkIO可以,新线程可以安全调用atomically。你可以这样做:

purifiedAlgorithm = unsafePerformIO $ do
  rr <- newEmptyMVar
  forkIO $ concurrentAlgorithm >> putMVar rr
  takeMVar rr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    相关资源
    最近更新 更多