在我正在编写的应用程序中,我需要编写许多基本类型,它们很可能是不可变的。但我想知道如何将并行应用程序中的可变类型与不可变类型进行比较。
您可以对可变对象使用锁,对吗?它与并行应用程序中使用不可变类型的其他技术相比如何?
你至少远离使用不可变类型的锁,对吧?
在我正在编写的应用程序中,我需要编写许多基本类型,它们很可能是不可变的。但我想知道如何将并行应用程序中的可变类型与不可变类型进行比较。
您可以对可变对象使用锁,对吗?它与并行应用程序中使用不可变类型的其他技术相比如何?
你至少远离使用不可变类型的锁,对吧?
类型
线程
如果您必须使用显式锁,请彻底记录它们。尤其是涉及到锁定对象的顺序时。如果你知道 Foo 对象总是在 Bar 对象之前被锁定并且 Foo(key 100) 总是在 Foo(key = 200) 之前被锁定,你就不会遇到死锁。
编写可并行化应用程序的关键是远离可变共享状态。在线程之间共享可变状态需要同步,这通常需要某种形式的锁定。使用不可变类型可以帮助确保您不会意外共享状态,因为无法更改这些对象的状态。然而,这不是灵丹妙药,而只是一种设计选择。如果您尝试并行化的算法需要共享状态,您将不得不创建某种同步。
可变性不影响锁定。
当您使用可变类型时,您将自己暴露于读后写或写后写错误。这些是与更新值相关的同步错误,而其他线程正在同时读取或更新该值。
为了防止同步错误,您必须使用某种形式的锁定机制。如果您确实使用显式锁定,则需要非常小心获取锁的顺序。如果你不小心,你可能会引入死锁。例如:线程 A 获得锁 X,然后线程 B 获得锁 Y。稍后,线程 A 请求锁 Y,线程 B 请求锁 X。这导致两个线程无限期地等待永远不会释放的锁。
锁定的两个好的经验法则:
如果您在创建对象后从未对其进行写入,则无需在访问之前锁定它。因此,您不需要锁定不可变对象。
尽可能使用不可变类型。必要时使用可变类型(序列化等)。
使用 System.Threading.Tasks 进行所有并行化 - 添加 async 和 await 关键字后,甚至可以使用 C# 5 中的语言构建任务。
我在 C# 中写了一篇关于可变/不可变类型的文章:http ://rickyhelgesson.wordpress.com/2012/07/17/mutable-or-immutable-in-a-parallel-world/