纯功能数据结构总是无锁吗?

时间:2014-04-16 17:05:42

标签: multithreading haskell data-structures functional-programming

我已经在多个地方看到过此声明,包括SO:https://stackoverflow.com/a/20467457/243238https://stackoverflow.com/a/4400389/243238。我认为修改数据不需要锁定,但在并发修改后最终会有多个版本。这在实践中似乎没有用。我试图通过以下简单的方案描述这一点:

假设我们有2个线程A和B.它们都修改了一个纯函数字典D.此时它们不需要锁,因为数据是不可变的,所以它们输出新的字典DA和D B。现在我的问题是如何协调DA和DB,以便以后的操作可以看到数据的单一视图?

编辑:答案建议在DA和DB上使用merge函数。我不知道如何解决问题,因为可能有另一个与合并操作同时运行的线程C.声称纯粹的功能数据结构是无锁的,但使用合并功能听起来更像是最终的一致性,这是另一回事。

5 个答案:

答案 0 :(得分:3)

功能数据结构的要点是原子性。在您的场景中,DA和DB保证一致,如何将它们合并为一致的值取决于您的应用程序(函数式编程不会为您解决所有问题)。然而,这仍然比你在命令式范例中得到的更多,其中DA和DB依赖于线程的排序方式。

答案 1 :(得分:3)

很好的观察。但这仅仅意味着在全球状态下存在并行性。无论编程语言如何,都很难或不可能。

在不纯的语言中,这不太明显。你可能认为你可以摆脱锁定,同步以及围绕它的所有高度复杂的代码。

而在纯语言中,你有n个纯状态变换器,并且不得不意识到如果你将它们应用于pareallel到某个初始状态S0,你最终会得到很多状态S1S2S3 ... Sn

现在,纯度只是保证S0的并行转换不会以任何方式相互干扰。它不能解决您的程序设计问题,例如该状态意味着什么,如果它可能太粗糙,或者太细粒度,并且您可以从各种转换状态计算最终结果。

答案 2 :(得分:2)

一般来说,有很多方法可以做到这一点。实际上,您可能希望确保DA或DB是规范的。如果无法做到那么应该有一个合并过程

Thread A/B: 

da  <- readSharedMemory at D
da' <- modifyDict da
mergeSharedMemory da'

其中mergeSharedMemory能够以一致的方式组合具有相似历史的两个词典。通常,这些类型的结构在数据库文献中作为CRDT-“会聚复制数据类型”和“可交换复制数据类型”进行了充分研究。 INRIA Paper有很多细节。

答案 3 :(得分:2)

纯函数数据结构是制作无锁可变数据结构的最简单的方法。给定一个任意的纯函数数据结构 T,您可以定义一个无锁可变数据结构 newtype U = U (IORef T)。给定一个任意函数 f :: T -> (T, a),你可以写

mf :: U -> IO a
mf (U ref) = atomicModifyIORef' ref f

那么,为什么会有大量关于制作无锁数据结构的奇特技术的文献呢?因为并非所有数据结构都可以以纯函数方式足够有效地实现。任何耗时过长的操作都会减慢所有线程的速度并导致更新积压。

答案 4 :(得分:1)

您创建第三个使用DA和DB生成DAB的函数。