将 Par monad 与 STM 和确定性 IO 结合使用

发布于 2024-12-09 18:32:41 字数 393 浏览 6 评论 0原文

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

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

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

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

I'm in the process of writing a report for an assignment in which I implemented a concurrent multicore branch and bound algorithm using the STM package and there was an issue I've come up against.

The implementation which uses STM is obviously in the IO monad since it both uses STM's 'atomically' and Concurrent's 'forkIO', but it is deterministic. Despite the use of a shared memory variable, the final result of the function will always be the same for the same input.

My question is, what are my options when it comes to getting out of IO, besides 'unsafePerformIO'? Should I even try and get it out of the IO monad, since the use of multiple cores could potentially affect other concurrent code that doesn't have the same guarantee for determinism.

I've heard of the Par monad package (although not used it), but STM exists in the IO monad, and in order to get thread safe global variables my only alternative to STM is MVars (that I'm aware of), which also exist in the IO monad.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

软的没边 2024-12-16 18:32:41

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

不安全 STM 操作不安全的一个例子是,您最终使用嵌套在另一个操作(可能是由更高级别的库)内的“纯”STM 操作。例如,由于嵌套的 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

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

Please do not use unsafePerformIO with STM. STM has side-effects under the hood, using unsafePerformIO hides these side effects, making your code deceptively impure and thus hard or dangerous to refactor. Try harder to see if the parallel package will help you.

One example of unsafe STM operations being unsafe is when you end up using the "pure" STM operation nested inside of another (perhaps by a higher level library). For example, the below code loops (terminates with <loop>) due to the nested STM operations. I recall older GHC versions crashing but can't seem to reproduce that behavior right now with 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

(I welcome other people editing and adding more convincing examples - I believe better ones exist)

北城孤痞 2024-12-16 18:32:41

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

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

STM and it's related functions cannot be used from unsafePerformIO but forkIO can be, and the new thread can call atomically safely. You can do something like this:

purifiedAlgorithm = unsafePerformIO $ do
  rr <- newEmptyMVar
  forkIO $ concurrentAlgorithm >> putMVar rr
  takeMVar rr
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文