并行应用程序的Mutable与Immutable

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

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

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

类型

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

主题

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

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

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

可变性不会影响锁定。

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

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

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

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

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

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

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

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