我正在编写一份报告,其中我使用STM包实现了并发多核分支和绑定算法,我遇到了一个问题。
使用STM的实现显然在IO monad中,因为它既使用STM的'atomically'和Concurrent的'forkIO',但它是确定性的。尽管使用了共享内存变量,但对于相同的输入,函数的最终结果将始终相同。
我的问题是,除了'unsafePerformIO'之外,在退出IO时我有哪些选择?我是否应该尝试将其从IO monad中删除,因为使用多个内核可能会影响对确定性没有相同保证的其他并发代码。
我听说过Par monad包(虽然没有使用它),但STM存在于IO monad中,为了获得线程安全的全局变量,我唯一的替代STM的是MVars(我知道的),也存在于IO monad中。
答案 0 :(得分:6)
请不要将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
(我欢迎其他人编辑和添加更有说服力的例子 - 我相信存在更好的例子)
答案 1 :(得分:0)
STM
并且它的相关功能无法在unsafePerformIO
中使用,但forkIO
可以使用,新线程可以安全地调用atomically
。你可以这样做:
purifiedAlgorithm = unsafePerformIO $ do
rr <- newEmptyMVar
forkIO $ concurrentAlgorithm >> putMVar rr
takeMVar rr