一种在没有轮询的情况下在MVars上形成"选择"的方法

Joh*_*ler 14 concurrency haskell transactional-memory

我有两个MVar(好吧是一个MVar和一个Chan).我需要从Chan中取出并处理它们,直到另一个MVar不再为空.我理想的解决方案就像UNIX select函数,我传入一个(可能是空的)MVar列表和线程块直到其中一个已满,然后它返回完整的MVar.尽量尝试我可以想到除了用isEmptyMVar重复轮询每个MVar之前没办法做到这一点,直到我弄错.这似乎效率低下.

一个不同的想法是使用throwTo,但它会中断线程中发生的事情,我需要以原子方式完成处理Chan的工作.

我正在打字的最后一个想法是为每个MVar创建一个新的forkIO,它试图读取它的MVar然后用自己的实例填充一个新创建的MVar.然后原始线程可以阻止该MVar.Haskell线程是否足够便宜,可以运行那么多?

ham*_*mar 16

Haskell线程非常便宜,所以你可以这样解决它,但听起来STM更适合你的问题.使用STM,你可以做到

do var <- atomically (takeTMVar a `orElse` takeTMVar b)
   ... do stuff with var
Run Code Online (Sandbox Code Playgroud)

由于行为retryorElse,此代码试图获得a,如果失败,拿到b.如果两者都失败,则会阻塞,直到其中任何一个更新并再次尝试.

您甚至可以使用它来制作自己的基本版本select:

select :: [TMVar a] -> STM a
select = foldr1 orElse . map takeTMVar
Run Code Online (Sandbox Code Playgroud)


Don*_*art 12

如何使用STM的版本,TChan并且TVar,与retryorElse行为?

实现select是STM的优秀功能之一.来自"可组合内存事务":

除此之外,我们还提供orElse,它允许将它们组合为替代方案,以便在第一次重试时运行第二个(第3.4节).这种能力允许线程一次等待很多事情,比如Unix select系统调用 - 除了orElse编写得好,而select不能.