【发布时间】:2010-11-24 13:08:46
【问题描述】:
有人告诉我 Clojure 具有无锁并发,这很重要。
我使用过多种语言,但没有意识到它们在幕后执行锁定。
为什么这是 Clojure(或任何具有此功能的语言)的优势?
【问题讨论】:
标签: concurrency clojure deadlock lock-free
有人告诉我 Clojure 具有无锁并发,这很重要。
我使用过多种语言,但没有意识到它们在幕后执行锁定。
为什么这是 Clojure(或任何具有此功能的语言)的优势?
【问题讨论】:
标签: concurrency clojure deadlock lock-free
无锁并发还提供了一个很好的优势,即读取器永远不必等待其他读取器。当许多线程将从单个源读取数据时,这尤其有用。您仍然需要在程序中定义数据依赖关系,并明确定义可以安全交换的事务部分。
STM 使您免于死锁和几乎所有活锁的发生,尽管它不能使您免于并发故障,您仍然可以创建事务失败的情况,因为它缺乏维护其历史的资源,但重要的部分是 并发故障将是明确的,您可以从中恢复
【讨论】:
readers never have to wait for other readers 在命令式世界中,读写锁提供了这个功能:)
我不能具体谈论 Clojure,但是……这意味着您无需等待某人完成某事才能开始工作。太棒了。
通常它是通过不可变类型实现的。如果没有任何东西可以修改,那么您实际上不需要等到其他人完成它才能访问它。
【讨论】:
死锁。或者更正确地说是缺少它们。
大多数语言的最大问题之一是您最终会遇到以下死锁:
现在没有锁,显然你不会遇到死锁。
【讨论】:
最大的问题是锁不构成。
虽然使用简单的锁定策略编写代码(例如,将其放在同步的 Java 类中......)是微不足道的,但当您开始锁定多个对象并开始创建复杂的事务时,它会变得更加复杂。结合不同的锁定操作。可能会发生死锁,性能受损,锁定逻辑开始使代码变得极其复杂,并且在某些时候代码开始变得不可维护。
对于必须构建大型复杂并发系统的任何人来说,这些问题都会变得显而易见(解决这些问题是 Rich Hickey 创建 Clojure 的主要动机)。
第二个问题是性能。
锁定和 STM 都明显增加了开销。但在某些重要情况下,STM 开销可能会低得多。
特别是,无锁并发(与 Clojure STM 一样)通常意味着如果读取器在事务之外访问数据,则不会受到任何其他线程(包括写入器!)的影响。在相当常见的情况下,这可能是一个巨大的胜利,读取不需要是事务性的并且大大超过写入(想想大多数 Web 应用程序......)。 Clojure 中对 STM 引用的非事务性读取基本上没有开销。
【讨论】:
Non-transactional reads of an STM reference in Clojure are essentially overhead free. 原则上事务性读取也应该如此? Doc 说“读者和通勤者永远不会阻止作家、通勤者或其他读者。”
只要您编写严格顺序的程序(执行 A,然后 B,然后 C;完成!),您就不会有并发问题,并且语言的并发机制仍然无关紧要。
当您从“编程练习”程序毕业到现实世界时,很快您就会遇到解决方案是多线程(或任何可用的并发)的问题。
案例:带有 GUI 的程序。假设您正在编写带有拼写检查功能的编辑器。您希望拼写检查器在后台安静地执行它的操作,但您希望 GUI 顺利接受用户输入。因此,您将这两个活动作为单独的线程运行。
案例:我最近编写了一个程序(用于工作),它从两个日志文件中收集统计信息并将它们写入数据库。处理每个文件大约需要 3 分钟。我将这些进程转移到两个并行运行的线程中,将总处理时间从 6 分钟缩短到 3 分钟多一点。
案例:科学/工程仿真软件。通过计算代表您的测试对象(星核、核爆炸、昆虫种群的地理分布......)的 3 维网格中每个点的一些效应(比如热流),可以解决很多很多问题。基本上每个点和很多点都进行相同的计算,所以让它们并行完成是有意义的。
在所有这些情况以及更多情况下,只要两个计算进程大致同时访问相同的内存(= 变量,如果您愿意的话),它们就有可能相互干扰并弄乱彼此的工作。处理“并发编程”的计算机科学的庞大分支处理有关如何解决此类问题的想法。
可以在in Wikipedia 找到有关此主题的相当有用的开始讨论。
【讨论】:
无锁并发的好处是程序不复杂。在命令式语言中,并发编程依赖于锁,一旦程序变得相当复杂,难以修复的死锁错误就会蔓延。
【讨论】:
这种“无锁并发”实际上并不是一种语言的特性;相反,它是平台或运行时环境的一项功能,不幸的是,这种语言不会让您访问这些设施。
考虑基于锁和无锁并发之间的交易类似于元循环求值器问题:一个可以用原子操作(例如比较和交换,或 CAS)来实现锁,一个可以实现原子锁方面的操作。哪个应该在底部?
【讨论】: