读取TChan会导致阻塞还是轮询?

Gre*_*ite 10 haskell ghc stm

首先,一些背景.我想要一个队列,我想以两种不同的模式之一操作.在第一种模式中,我希望能够检索队列中存在的元素,但是如果没有元素则不能阻止.在第二种模式中,我希望能够阻塞,直到队列中有一个元素.(我知道我可以为每种模式使用专门的机制,但我想分解一些常用代码,因此如果我可以对两种操作模式使用相同的机制,那将是最简单的.)

我可以使用Chan,但根据我不应该使用的文档,isEmptyChan因为它可能会因为死锁而被弃用.这让我失望了TChan.该tryReadTChan函数为我提供了我想要的第一种模式(即我可以检查元素是否存在而没有阻塞),但我不确定究竟是什么readTChan.我的心智模型是该atomically块将继续重试,直到通道中存在一个元素,这意味着它将忙于循环浪费CPU周期; 这是不同的readChan(即,非STM版本)(如果我理解正确的话)将实际阻止线程的执行,直到元素可用,因为运行时线程调度程序理解MVars.

那么,TChan就像Chan在,如果我使用readTChan了运行时是足够聪明,直到值可用不安排调用线程?或者它会浪费大量的CPU周期不断轮询到一个值到达?

sha*_*haf 14

STM阻塞(via retry)就像它立即重试事务一样,但实现更聪明:由于STM跟踪事务继续时读取的变量,它知道事务的行为方式与那些变量具有相同的值.因此,当事务失败时,它将阻止(实际上不会重试),直到您使用的其中一个变量发生更改.在TChans 的情况下,这意味着它会阻止,直到有人写入TChan.

我推荐Simon Marlow 在并发和并行Haskell上的幻灯片,以便对STM(以及其他内容)有一个很好的介绍.


Car*_*arl 11

您的心理模型具有正确的指称语义,但是错过了STM的操作优化.当事务在STM中重试时,它将阻塞,直到TVar重试更改之前读取的某些事务为止.(是的,TChan是以实施的方式实施的TVar.)

因此,执行事务具有与事务不断重试相同的含义 - 但是如果在事务中没有可能出现不同的事情,则STM系统足够聪明,不会忙于循环.