6

有人告诉我 Clojure 具有无锁并发,这很重要。

我使用了多种语言,但没有意识到它们在幕后执行锁定。

为什么这是 Clojure(或任何具有此功能的语言)的优势?

4

7 回答 7

9

无锁并发还提供了读者永远不必等待其他读者的好处。当许多线程将从单个源读取数据时,这尤其有用。您仍然需要在程序中定义数据依赖关系,并明确定义可以安全交换的事务部分。
STM 使您免于死锁和几乎所有活锁的发生,尽管它不能使您免于并发故障,您仍然可以创建事务失败的情况,因为它缺乏维护其历史的资源,但重要的部分是并发故障将是显式的你可以从他们那里恢复

于 2009-09-01T18:27:12.630 回答
8

我不能具体谈论 Clojure,但是……这意味着您无需等待某人完成某事即可开始工作。这是伟大的。

通常它是通过不可变类型实现的。如果没有任何东西可以修改,那么您实际上不需要等到其他人完成它才能访问它。

于 2009-09-01T05:58:39.960 回答
5

死锁。或者更正确地说是缺少它们。

大多数语言中最大的问题之一是您最终会遇到以下死锁:

  1. 人间地狱调试。
  2. 很难确定你已经摆脱了。

现在没有锁,显然你不会遇到死锁。

于 2009-09-01T06:08:01.157 回答
5

最大的问题是锁不组合

虽然使用简单的锁定策略编写代码(例如,将其放在同步的 Java 类中......)是微不足道的,但当您开始锁定多个对象并开始创建组合不同锁定的复杂事务时,它会变得复杂得多操作。可能会发生死锁,性能受到影响,锁定逻辑开始使代码变得非常复杂,并且在某些时候代码开始变得不可维护。

对于必须构建大型复杂并发系统的任何人来说,这些问题都将变得显而易见(解决这些问题是 Rich Hickey 创建 Clojure 的主要动机)。

第二个问题是性能

锁定和 STM 都明显增加了开销。但在某些重要情况下,STM 开销可能会低得多。

特别是,无锁并发(与 Clojure STM 一样)通常意味着读取器在访问事务之外的数据时不会受到任何其他线程(包括写入器!)的影响。在相当普遍的情况下,这可能是一个巨大的胜利,读取不需要是事务性的并且大大超过写入(想想大多数 Web 应用程序......)。Clojure 中对 STM 引用的非事务性读取基本上是无开销的。

于 2011-01-08T13:45:48.037 回答
2

只要您编写严格的顺序程序(执行 A,然后 B,然后 C;完成!)您就不会遇到并发问题,并且语言的并发机制仍然无关紧要。

当您从“编程练习”程序毕业到现实世界的东西时,很快您就会遇到解决方案是多线程(或任何可用的并发性)的问题。

案例:带有 GUI 的程序。假设您正在编写带有拼写检查功能的编辑器。您希望拼写检查器在后台安静地执行其操作,但您希望 GUI 能够顺利接受用户输入。因此,您将这两个活动作为单独的线程运行。

案例:我最近编写了一个程序(用于工作),它从两个日志文件中收集统计信息并将它们写入数据库。处理每个文件大约需要 3 分钟。我将这些进程转移到两个并行运行的线程中,将总处理时间从 6 分钟缩短到 3 分钟多一点。

案例:科学/工程仿真软件。通过计算代表您的测试对象(星核、核爆炸、昆虫种群的地理分布......)的 3 维网格中每个点的一些效应(比如热流),可以解决很多很多问题。基本上每个点和很多点都进行相同的计算,所以让它们并行完成是有意义的。

在所有这些情况以及更多情况下,每当两个计算进程大致同时访问相同的内存(= 变量,如果你愿意的话),它们就有可能相互干扰并弄乱彼此的工作。处理“并发编程”的计算机科学的庞大分支处理有关如何解决此类问题的想法。

可以在 Wikipedia中找到有关该主题的相当有用的开始讨论。

于 2009-09-26T09:34:23.960 回答
1

无锁并发的好处是程序不复杂。在命令式语言中,并发编程依赖于锁,一旦程序变得相当复杂,难以修复的死锁错误就会出现。

于 2009-09-01T06:08:37.553 回答
0

这种“无锁并发”并不是一种语言的真正特性;相反,它是平台或运行时环境的一个特性,不幸的是,这种语言不会让您访问这些设施。

考虑基于锁并发和无锁并发之间的交易类似于元循环求值器问题:可以用原子操作(例如比较和交换,或 CAS)来实现锁,并且可以用原子操作来实现的锁。哪个应该在底部?

于 2009-11-07T23:43:42.193 回答