Haskell 何时/为什么在TVar上使用MVar

Haskell 何时/为什么在TVar上使用MVar,haskell,shared-memory,stm,Haskell,Shared Memory,Stm,我发现TVar很容易使用,尽管MVar看起来更简单,而TVar则更有特色 所以我的问题很简单,什么条件下我想去MVar而不是TVar?我想只要我不需要事务性更新,我就可以使用MVar,但这对我有什么好处呢?TVAR更安全,但速度较慢 MVAR可以死锁,但效率要高得多 更有效的方法仍然是IORef和atomicModifyIORef(CAS),但这在您可以使用它时受到很大限制 这确实是一种安全性高于性能的权衡。TVAR是完全通用的,非常安全。其他一切都不是这样,只是规模在缩小。MVar 可以是空

我发现TVar很容易使用,尽管MVar看起来更简单,而TVar则更有特色


所以我的问题很简单,什么条件下我想去MVar而不是TVar?我想只要我不需要事务性更新,我就可以使用MVar,但这对我有什么好处呢?

TVAR更安全,但速度较慢

MVAR可以死锁,但效率要高得多

更有效的方法仍然是
IORef
atomicModifyIORef
(CAS),但这在您可以使用它时受到很大限制

这确实是一种安全性高于性能的权衡。TVAR是完全通用的,非常安全。其他一切都不是这样,只是规模在缩小。

MVar

  • 可以是空的
  • 用于实现线程之间的同步模式
  • 允许线程之间的单向通信
  • 在某些情况下可能比TVar快
TVar

  • 不能为空吗
  • 原子事务
  • 线程之间的“共享内存”;例如,可以用来实现一个查找缓存,多个线程可以从中读/写
  • 访问是事务日志中操作数的线性时间
  • 如果存在许多较短的事务,则长时间运行的事务很容易饿死,从而阻止它们成功提交
IORef

  • 可变指针式引用
  • 通常用于破坏性的
    IO
    写入/更新
  • 具有原子CAS操作,但复杂的事务逻辑更适合
    TVar
对于何时使用
MVar
TVar
,实际上没有一个硬性规定。
如果我所保护的资源将永远是“缺失”(与空相反,考虑<代码>没有< /COD> VS <代码>只是MimpTy <代码> >,那么<代码> MVar < /代码>常常是最有意义的。如果我需要对资源执行原子块修改,那么
TVar
最合适。

效率,良好的“nuff”。我觉得它们的性能也很相似,所以这个故事很有寓意:如果你需要事务性更新,就使用TVar,否则就使用MVar,因为它会大大降低你的多线程应用程序的速度,没有人能量化实际的速度差吗?(这可能很难衡量,因为它取决于实际的线程交互…@MathematicalOrchid忽略并发问题:读写
IORef
将是最快的操作,但是GHC 7.8附带了一些对
MVar
的改进,在
读/写权限
的几纳秒内带来了
takeMVar/putMVar
(比如在我的机器上是9.7/4.6 vs 3.7/7/3()),我们还有一个新的非常快速的
readMVar
(当MVar满了的时候)。此外,由于某种原因,atomicModifyIORef在争用下的性能非常差。@MathematicalArchid我曾尝试过一次对TVars
vs
modifyIORef
进行基准测试。我做了一些银行账户的事情,每个线程将在两个银行账户之间进行交易。
IORef
实现将以明显的不一致性结束。我的第一次尝试使一个随机数发生器成为工作台,第二次尝试使一个更快的随机数发生器成为工作台。在第三次尝试时,我得到了一个速度差(~快了一倍),我的随机生成器实际上根本不是随机的,只是从数组中获取预生成的数字。在那一点上,我意识到我不知道我在做什么,所以我放弃了。你指的是线程通信的共享MVar,它们不应该只用于单向通信吗?因为如果两个线程都在更新同一个MVar以进行来回通信,它们将有竞争条件?你是正确的。我并不是说两个线程都会更新相同的
MVar
,我会更清楚地说明这一点。我可能还想添加一个关于饥饿的注释。MVar保证是公平的,而TVAR则不是。Jimmyhoff您可以使用
MVar
有几种模式,例如:一些线程将其他线程放入(本质上是一个1元FIFO队列);许多线程执行
modifyMVar
来修改某些共享状态;线程在进入一个临界段之前先取一个
()
,然后在退出时替换(将其用作锁),等等。