【发布时间】:2012-04-30 12:40:16
【问题描述】:
我一直在尝试了解并发性,并且一直在尝试找出更好的方法,一个大的IORef 锁或多个TVars。我已经得出以下指导方针,我们将不胜感激,关于这些是否大致正确或我是否错过了重点。
假设我们的并发数据结构是一个映射m,访问类似于m[i]。假设我们有两个函数,f_easy 和 f_hard。 f_easy 很快,f_hard 需要很长时间。我们假设f_easy/f_hard 的参数是m 的元素。
(1) 如果您的交易大致类似于 m[f_easy(...)] = f_hard(...),请使用 IORef 和 atomicModifyIORef。懒惰将确保m 仅在短时间内被锁定,因为它会使用 thunk 进行更新。计算索引有效地锁定了结构(因为有些东西会被更新,但我们还不知道是什么),但是一旦知道那个元素是什么,整个结构上的 thunk 就会移动到仅在那个特定元素上的 thunk ,然后只有那个特定的元素被“锁定”。
(2) 如果你的事务大致像这样m[f_hard(...)] = f_easy(...),并且不要冲突太多,请使用大量TVars。在这种情况下使用IORef 将有效地使应用程序成为单线程,因为您不能同时计算两个索引(因为整个结构上会有一个未解决的thunk)。 TVars 让你同时计算出两个索引,但是,不利的是,如果两个并发事务都访问同一个元素,并且其中一个是写入,则必须废弃一个事务,这会浪费时间(可以在其他地方使用)。如果这种情况经常发生,你可能会更好地使用来自IORef 的锁(通过黑洞),但如果它不会发生很多,你将获得更好的并行性TVars。
基本上在情况 (2) 中,使用 IORef 您可能会获得 100% 的效率(不会浪费工作),但只使用 1.1 个线程,但使用 TVar 如果您的冲突数量很少,您可能会获得 80% 的效率但是使用 10 个线程,因此即使浪费了工作,您最终仍能快 7 倍。
【问题讨论】:
-
这里有问题吗?我很惊讶
MVar完全缺席。 -
获得“安全”变量然后拥有多个线程的另一种方法是使用通道 (haskell.org/ghc/docs/latest/html/libraries/base/…) 并拥有一个监督所有值的线程,其他线程必须联系该线程才能获得访问值
标签: performance haskell concurrency ioref