我有两个MVar(一个MVar和一个Chan)。我需要从Chan中取出并处理它们,直到其他MVar不再为空。我理想的解决方案就像UNIX select
函数,我传入一个(可能是空的)MVar列表和线程块直到其中一个已满,然后它返回完整的MVar。尽量尝试我可以想到除了用isEmptyMVar重复轮询每个MVar之前没办法做到这一点,直到我弄错。这似乎效率低下。
另一个想法是使用throwTo,但它会中断线程中发生的事情,我需要以原子方式完成处理Chan的工作。
我正在输入的最后一个想法是为每个MVar创建一个新的forkIO,它试图读取它的MVar然后用自己的实例填充一个新创建的MVar。然后原始线程可以阻止该MVar。 Haskell线程是否足够便宜以运行那么多?
答案 0 :(得分:16)
Haskell线程非常便宜,所以你可以这样解决它,但听起来STM更适合你的问题。使用STM,你可以做到
do var <- atomically (takeTMVar a `orElse` takeTMVar b)
... do stuff with var
由于retry
和orElse
的行为,此代码尝试获取a
,如果失败,则获取b
。如果两者都失败,则会阻塞,直到其中任何一个更新并再次尝试。
您甚至可以使用它来制作自己的select
的基本版本:
select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar
答案 1 :(得分:12)
使用TChan
和TVar
行为的STM版本retry
和orElse
怎么样?
实现select是STM的优秀功能之一。来自“可组合记忆交易”:
除此之外,我们还提供orElse, 这使得它们可以作为替代品组成 第二次运行如果第一次重试(第3.4节)。这种能力允许线程一次等待很多事情,比如 Unix选择系统调用 - 除了orElse编写得好, 而选择没有。