Clojure是否使用lockfree算法无锁?

时间:2012-06-14 11:14:14

标签: concurrency clojure locking lock-free lockless

我正在进行我的Clojure任务(在4clojure.com上解决了大约80个问题)并继续阅读和编码并试图“搞定”。

现在我对Clojure被设计为“无锁并发”感到困惑。我非常了解死锁(例如:“我编写了糟糕的Java代码,最终导致死锁”,而不是像那样“我是并发专家”)。我也读过这个:

Why is lockless concurrency such a big deal (in Clojure)?

我意识到Clojure程序无法解决僵局。

但我有点困惑:通过在引擎盖下无锁算法实现或者是否使用了可能的“死锁”算法实现了这样的壮举,但使用正确的实现保证永远不会死锁(这会以某种方式“隐藏”到Clojure程序员)?

最近讨论过关于无锁算法的黑客新闻:

http://news.ycombinator.com/item?id=4103921

1024cores.net 上引用以下“无锁算法”页面:

http://www.1024cores.net/home/lock-free-algorithms

我不明白这篇文章与Clojure下的并发工作方式之间的关系。

它让我完全糊涂了:当我在Clojure中开发并发程序时,它是否意味着“锁定和无锁算法”对我来说不是问题?

2 个答案:

答案 0 :(得分:9)

一般情况下,Clojure通过正确处理时间来避免锁定问题在许多系统中,对象的时间是一个非常松散的概念,因为在时间1(在更新之前)的对象被编辑到位在时间-2(更新后)成为该对象,在该过程中它是第一个或第二个,因此我们使用锁来确保它仅在此转换之前或之后可见。协调锁定来自于此......以及...的死锁。

它是算法,数据结构和时间的组合。

Clojure通过组合不可变数据结构,函数式编程和协调时间模型(refs,atoms,agents等)来实现这一点。在这个模型中,一个函数需要一些东西并生成它的下一个版本,同时保留过去只要有人看到它(直到GC到达它)

  • 不可变数据结构:Clojure的集合在单词的FP意义上是持久的。新版本制作完成后,旧副本将“保留”。这样观察者就不需要锁定对象,因为它们永远不会从它们下面改变。可能存在基于他们正在查看的版本的较新版本,但没有任何内容会更改其副本。

  • 功能编程:纯粹(或尽可能接近)功能在一个时间点收集一个集合并生成下一个版本而不共享其内部状态,因此不需要锁定。这也有许多其他好处。

  • Coordinated time:当需要协调多个对象时,就像任何有趣的系统一样,那么Clojure的时间模型就会发挥作用。存在用于不同目的的不同机制。这有一个内部用于计算时间增量的锁,因此恰好有一个零时间,一个时间和一个时间N.所以它不是严格锁定的。 STM包含您永远不需要与之交互的锁

<小时/> *好......几乎从不; - )

答案 1 :(得分:4)

如果你围绕Clojure源代码,特别是.java文件,你会发现很多对java.util.concurrent包的引用。 java.util.concurrent一揽子计划是几十年来纽约州立大学奥斯威戈分校Doug Lea对并发性研究的结晶。具体来说,有一些原子变量类(例如AtomicReference)的引用允许访问“比较和交换”(也称为“比较和设置”或CAS)instruction。 CAS指令有点难以解释(我在下面提供了参考),但正确使用CAS是算法“无锁”的核心(至少在Java世界中)。无锁算法最终可以提高吞吐量,减少高度并发应用程序的争用;正是Clojure所针对的领域。

要深入了解此主题,请阅读Brian Goetz撰写的 Java Concurrency in Practice 。另请参见同一作者的article

作为旁注,我总是发现很难直接使用java.util.concurrent包,即使它已经发展。它对我来说感觉太低了。关于Clojure的精彩之处在于它提供了对专家并发库的访问,但是通过极好的易用软件事务内存(STM)抽象。这真的是一个很大的成就。