我正在考虑使用TVar在Web应用程序中存储某些状态(可以在重新启动时重新创建)。然而,TVar的争论方面关注我。似乎频繁的短期交易可以通过不断地中断它们来匮乏更长的交易。此外,随着更长时间运行的事务不断重启,这会增加CPU的负载,趋向于进一步增加这些事务的长度。最终我觉得这可能会导致服务器完全没有响应。
考虑到这一点,我有以下问题:
(1)TVar(或其他数据类型)可以使用锁定,而不是同时尝试/重试。
(2)TVar(或其他数据类型)可以有一些不同的争用机制,即“让事务在运行另一个事务之前运行一秒钟”,或者至少保证交易最终会完成(即争用算法,阻止starvation更长时间运行的事务。)
答案 0 :(得分:5)
除非您更改STM系统本身的运行时代码,否则我认为没有办法保证饥饿自由。在我看来,引入锁以避免TVars
之间的争用首先使STM失败的目的,因为使用STM的全部目的是摆脱经典的容易出错的基于锁的并发方法节目。
当然,饥饿可能会导致严重的性能损失,但只能假设这样的大型交易实际上是必要的。我试图记住的一个设计原则是在低粒度级别使用TVars
。例如,不是将整个Data.Map
放入TVar
,而是每次更新条目时都可能导致争用,
你可以使用更像STM的数据结构,比如跳过列表[1]。
答案 1 :(得分:3)
如果您有许多更新数据的廉价交易和一些阅读数据的昂贵交易,这只是一个问题。也许在实时更新的数据集上进行分析。
如果您真的关心这一点,请考虑使用标志TVar。将其设置为false并在每个廉价交易开始时检查它是否为假,否则调用retry
。然后在进入longrunning事务之前将其设置为true,并在退出时将其设置为false。或者,您可以简单地在TMVar
后面保护您的状态。您的longrunning计算以原子方式获取tmvar,执行它的感觉,然后返回它。其他交易完全在一个实际的STM交易中进行。
还要记住,长时间运行的STM事务是一种棘手的野兽。由于懒惰,你可以廉价地将一个昂贵的价值放入var。您还可以非常快速地从一大堆变量中读取数据的“快照”。要拥有一个真正长时间运行的事务,您需要从一大堆变量中读取,然后根据您所读取的内容,计算您要将新值写入的变量(或读取值)来自),并且计算本身必须是昂贵的。很可能你甚至不会在那种情况下开始!
答案 2 :(得分:0)
这是对克林顿对彼得斯回答的评论之一的评论。但它变得很长。
考虑一下,您有两个银行账户:A和B.每个账户都有自己的锁保护。现在,您有两个交易,第一个转移资金从A到B,第二个从B转移到A.每个首先锁定源帐户,然后是目标帐户,转移资金并释放锁定。如果你不幸的话,这两个交易将陷入死锁,并且这两个账户都不会做任何事情。如果你在STM中这样做,他们会互相追逐。如果你有很多第一种,他们可能会饿死第二次交易。但是你还是做了很多。虽然锁定没有任何事情发生。
STM保证与TVars没有数据竞争!没有任何。通过锁定,您可以在仔细检查代码后得出结论。你添加的每一行都可能完全无效。