并行应用程序的Mutable与Immutable

时间:2009-05-20 19:33:58

标签: c# .net parallel-processing immutability mutable

在我写的应用程序中,我需要编写很多基类型,这很可能是不可变的。但我想知道可变类型在并行应用程序中如何与不可变类型进行比较。

你可以使用带有可变对象的锁,对吗?它与并行应用程序中不可变类型使用的其他技术相比如何?

你至少不使用具有不可变类型的锁,对吗?

4 个答案:

答案 0 :(得分:7)

类型

  • 尽可能使用不可变类型。
  • 尽可能使用线程安全集合而不是显式锁。
  • 只有在没有其他合理选择时才使用可变类型。

线程

  • 尽可能使用线程池。
  • 当无法使用线程池时使用无限循环。
  • 手动启动和停止线程作为最后的手段。

如果必须使用显式锁定,请将它们记录下来。特别是在锁定对象的顺序方面。如果你知道Foo对象总是在Bar对象之前被锁定,并且Foo(key 100)总是在Foo(key = 200)之前被锁定,你将不会遇到死锁。

答案 1 :(得分:3)

编写可并行化应用程序的关键是远离可变共享状态。在线程之间共享可变状态需要同步,这通常需要某种形式的锁定。使用不可变类型可以帮助确保您不会意外地共享状态,因为无法更改这些对象的状态。然而,这不是一个神奇的子弹,而只是一个设计选择。如果您尝试并行化的算法需要共享状态,则必须创建某种同步。

可变性不会影响锁定。

答案 2 :(得分:1)

当您使用可变类型时,您将自己暴露于Write-After-Read或Write-After-Write错误。这些是与更新值相关的同步错误,而其他线程同时读取或更新值。

要防止同步错误,您必须使用某种形式的锁定机制。如果使用显式锁定,则需要非常小心获取锁定的顺序。如果你不小心你可以引入死锁。例如:线程A获取锁定X,然后线程B获取锁定Y.稍后,线程A请求锁定Y,线程B请求锁定X.这会导致两个线程无限期地等待永远不会释放的锁定。

锁定的两个好的经验法则:

  • 以特定顺序获取锁定(例如,在锁定Y之前始终获取锁定X)
  • 尽可能短的时间保持锁定。在需要时获取它们,并在完成后立即释放它们。

如果您在创建对象后从不写入对象,则无需在访问对象之前将其锁定。因此,您不需要锁定不可变对象。

答案 3 :(得分:0)

尽可能使用不可变类型。必要时使用可变类型(序列化等)。

使用System.Threading.Tasks实现所有并行化 - 当添加async和await关键字时,任务甚至可以使用C#5中的语言构建。

我在C#中写了一篇关于可变/不可变类型的文章:http://rickyhelgesson.wordpress.com/2012/07/17/mutable-or-immutable-in-a-parallel-world/