Use thread-safe collections instead of explicit locks as much as possible.
Only use mutable types when you have no other reasonable choice.
Threads
Use thread pools as much as possible.
Use endless loops when thread pools aren't possible.
Manually start and stop threads as a last resort.
If you do have to use explicit locks, document them throughly. Especially when it comes to the order in which you lock objects. If you know that Foo objects are always locked before Bar objects and that Foo(key 100) is always locked before Foo(key = 200), you won't get deadlocks.
The key to writing parallelizable applications is to stay away from mutable shared state. Sharing mutable state between threads requires synchronization which typically entails some form of locking. Using immutable types can help ensure that you are not accidentally sharing state, by making it impossible to change the state of those objects. However, this is not a magic bullet, but simply a design choice. If the algorithm you are attempting to parallelize requires shared state, you are going to have to create some sort of synchronization.
为了防止同步错误,您必须使用某种形式的锁定机制。 如果您确实使用显式锁定,则需要非常小心获取锁的顺序。 如果不小心,可能会导致死锁。 例如:线程 A 获取锁 X,然后线程 B 获取锁 Y。稍后线程 A 请求锁 Y,线程 B 请求锁 X。这会导致两个线程无限期地等待永远不会释放的锁。
锁定的两个好的经验法则:
以特定顺序获取锁(例如,始终在锁 Y 之前获取锁 X)
保持锁的时间尽可能短。 在需要时获取它们,并在使用完毕后立即释放它们。
如果您在创建对象后从未对其进行写入,则无需在访问它之前锁定它。 因此,您不需要锁定不可变对象。
When you use mutable types you are exposing yourself to Write-After-Read or Write-After-Write errors. These are synchronisation errors associated with updating a value while other threads are concurrently reading or updating the value.
To prevent synchronization errors you must use some form of locking mechanism. If you do use explicit locking you will need to be very careful about the order of acquiring locks. If you are not careful you can introduce deadlocks. For example: Thread A acquires Lock X, then Thread B acquires Lock Y. A while later Thread A requests Lock Y and Thread B requests Lock X. This causes both threads to wait indefinitely for Locks that will never be released.
Two good rules of thumb for locking:
Acquire locks in a specific order (e.g. always acquire Lock X before Lock Y)
Hold locks for as short a time as possible. Acquire them when you need them, and release them as soon as you're done with the.
If you never write to an object after its creation, you do not need to lock it before accessing it. Thus, you will not need to lock immutable objects.
Use immutable types when you can. Use mutable types when you have to (serialization etc.).
Use System.Threading.Tasks for all your parallelization - Tasks will even be build in with the language in C# 5 when async and await keywords are added.
发布评论
评论(4)
类型
线程
如果您确实必须使用显式锁,请详细记录它们。 特别是当涉及到锁定对象的顺序时。 如果您知道 Foo 对象始终在 Bar 对象之前锁定,并且 Foo(key 100) 始终在 Foo(key = 200) 之前锁定,则不会出现死锁。
Types
Threads
If you do have to use explicit locks, document them throughly. Especially when it comes to the order in which you lock objects. If you know that Foo objects are always locked before Bar objects and that Foo(key 100) is always locked before Foo(key = 200), you won't get deadlocks.
编写可并行应用程序的关键是远离可变共享状态。 在线程之间共享可变状态需要同步,这通常需要某种形式的锁定。 使用不可变类型可以帮助确保您不会意外共享状态,因为无法更改这些对象的状态。 然而,这并不是灵丹妙药,而只是一种设计选择。 如果您尝试并行化的算法需要共享状态,则您将必须创建某种同步。
可变性不会影响锁定。
The key to writing parallelizable applications is to stay away from mutable shared state. Sharing mutable state between threads requires synchronization which typically entails some form of locking. Using immutable types can help ensure that you are not accidentally sharing state, by making it impossible to change the state of those objects. However, this is not a magic bullet, but simply a design choice. If the algorithm you are attempting to parallelize requires shared state, you are going to have to create some sort of synchronization.
Mutability does not affect locking.
当您使用可变类型时,您将面临“读后写”或“写后写”错误。 这些是与在其他线程同时读取或更新该值时更新该值相关的同步错误。
为了防止同步错误,您必须使用某种形式的锁定机制。 如果您确实使用显式锁定,则需要非常小心获取锁的顺序。 如果不小心,可能会导致死锁。 例如:线程 A 获取锁 X,然后线程 B 获取锁 Y。稍后线程 A 请求锁 Y,线程 B 请求锁 X。这会导致两个线程无限期地等待永远不会释放的锁。
锁定的两个好的经验法则:
如果您在创建对象后从未对其进行写入,则无需在访问它之前锁定它。 因此,您不需要锁定不可变对象。
When you use mutable types you are exposing yourself to Write-After-Read or Write-After-Write errors. These are synchronisation errors associated with updating a value while other threads are concurrently reading or updating the value.
To prevent synchronization errors you must use some form of locking mechanism. If you do use explicit locking you will need to be very careful about the order of acquiring locks. If you are not careful you can introduce deadlocks. For example: Thread A acquires Lock X, then Thread B acquires Lock Y. A while later Thread A requests Lock Y and Thread B requests Lock X. This causes both threads to wait indefinitely for Locks that will never be released.
Two good rules of thumb for locking:
If you never write to an object after its creation, you do not need to lock it before accessing it. Thus, you will not need to lock immutable objects.
尽可能使用不可变类型。 必要时使用可变类型(序列化等)。
使用 System.Threading.Tasks 进行所有并行化 - 当添加 async 和 wait 关键字时,甚至可以使用 C# 5 语言构建任务。
我写了一篇关于 C# 中可变/不可变类型的文章: http://rickyhelgesson.wordpress.com/2012/07/17/mutable-or-immutable-in-a-parallel-world/
Use immutable types when you can. Use mutable types when you have to (serialization etc.).
Use System.Threading.Tasks for all your parallelization - Tasks will even be build in with the language in C# 5 when async and await keywords are added.
I wrote an article on mutable / immutable types in C#: http://rickyhelgesson.wordpress.com/2012/07/17/mutable-or-immutable-in-a-parallel-world/