我正在尝试思考如何在 Haskell 中的线程之间正确通信。
我有多个线程读取某些状态,每当状态发生变化时,它们都需要进行一些更新。然后我有多个线程可以改变该状态。
我首先查看了 MVar,但这不行,因为它在写入时会阻塞,并且只有一个线程可以读取。
我发现的最好的东西是 TVar,我可以向它写入并从中读取当前状态。因此,我可以让读取的线程每秒左右轮询一次状态的更改(小延迟并不重要,线程可能会错过状态之间的情况也不重要)。那会起作用的。
但是,我想知道,有没有一种不需要轮询的方法?我可以使用其他一些原语吗?或者我可以“听” TVar 的方式?
retry
。
onChanges :: Eq a => (a -> IO ()) -> TVar a -> IO b
onChanges f tvar = readTVarIO tvar >>= go where
go a = do
a' <- atomically do
a' <- readTVar tvar
when (a == a') retry
pure a'
f a'
go a'
别担心——这并不贵。每个retry
都会阻塞,直到再次写入
TVar
。如果与运行
f
相比,相等性检查的成本较高,或者如果您想在每次写入时运行
f
,即使值没有更改,您也可以在
Int
中存储
TVar
或类似内容已经被写入了多少次,并检查它来决定是否
retry
。