Haskell 何时/为什么在TVar上使用MVar
我发现TVar很容易使用,尽管MVar看起来更简单,而TVar则更有特色Haskell 何时/为什么在TVar上使用MVar,haskell,shared-memory,stm,Haskell,Shared Memory,Stm,我发现TVar很容易使用,尽管MVar看起来更简单,而TVar则更有特色 所以我的问题很简单,什么条件下我想去MVar而不是TVar?我想只要我不需要事务性更新,我就可以使用MVar,但这对我有什么好处呢?TVAR更安全,但速度较慢 MVAR可以死锁,但效率要高得多 更有效的方法仍然是IORef和atomicModifyIORef(CAS),但这在您可以使用它时受到很大限制 这确实是一种安全性高于性能的权衡。TVAR是完全通用的,非常安全。其他一切都不是这样,只是规模在缩小。MVar 可以是空
所以我的问题很简单,什么条件下我想去MVar而不是TVar?我想只要我不需要事务性更新,我就可以使用MVar,但这对我有什么好处呢?TVAR更安全,但速度较慢 MVAR可以死锁,但效率要高得多 更有效的方法仍然是
IORef
和atomicModifyIORef
(CAS),但这在您可以使用它时受到很大限制
这确实是一种安全性高于性能的权衡。TVAR是完全通用的,非常安全。其他一切都不是这样,只是规模在缩小。MVar
- 可以是空的
- 用于实现线程之间的同步模式
- 允许线程之间的单向通信
- 在某些情况下可能比TVar快
- 不能为空吗
- 原子事务
- 线程之间的“共享内存”;例如,可以用来实现一个查找缓存,多个线程可以从中读/写
- 访问是事务日志中操作数的线性时间
- 如果存在许多较短的事务,则长时间运行的事务很容易饿死,从而阻止它们成功提交
- 可变指针式引用
- 通常用于破坏性的
写入/更新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
vsmodifyIORef
进行基准测试。我做了一些银行账户的事情,每个线程将在两个银行账户之间进行交易。IORef
实现将以明显的不一致性结束。我的第一次尝试使一个随机数发生器成为工作台,第二次尝试使一个更快的随机数发生器成为工作台。在第三次尝试时,我得到了一个速度差(~快了一倍),我的随机生成器实际上根本不是随机的,只是从数组中获取预生成的数字。在那一点上,我意识到我不知道我在做什么,所以我放弃了。你指的是线程通信的共享MVar,它们不应该只用于单向通信吗?因为如果两个线程都在更新同一个MVar以进行来回通信,它们将有竞争条件?你是正确的。我并不是说两个线程都会更新相同的MVar
,我会更清楚地说明这一点。我可能还想添加一个关于饥饿的注释。MVar保证是公平的,而TVAR则不是。Jimmyhoff您可以使用MVar
有几种模式,例如:一些线程将其他线程放入(本质上是一个1元FIFO队列);许多线程执行modifyMVar
来修改某些共享状态;线程在进入一个临界段之前先取一个()
,然后在退出时替换(将其用作锁),等等。