什么是正确的代码区锁定方式?

5
什么更好:
在锁语句中有一个大的代码区域
还是
在一个大的区域中有小的锁?..
此示例中的交换是不可改变的。
lock (padLock)
{
  foreach (string ex in exchanges)
  {
     sub.Add(x.ID, new Subscription(ch, queue.QueueName, true));
.........
}

或者

foreach (string ex in exchanges)
{
  lock (padLock) 
  {
     sub.Add(x.ID, new Subscription(ch, queue.QueueName, true));
  }
.....

2
这完全取决于你正在寻找什么。 - SLaks
@SLaks,我觉得我不太明白什么时候该使用锁定机制.. :( - 0x49D1
1
你的示例未完成,因此在问题范围内没有意义,因为循环中既未使用“ex”也未使用“exchanges”,因此很难向您提供具体建议。 - sll
1
如果你不理解何时使用锁定,请不要去使用它。否则你最终会遇到竞争条件、死锁或完全缺乏并行性的问题。 - SLaks
@SLaks,但我必须将一些东西并行处理。现在,我试图在所有“并行”代码部分中更改的位置上放置锁定。 - 0x49D1
显示剩余3条评论
5个回答

1

良好的实践是只锁定您希望在给定时间内由一个线程执行的区域

如果该区域是整个foreach循环,则第一种方法是可以接受的

但是,如果该区域仅为您展示的一行,则建议采用第二种方法


1

锁范围越广,多线程效率就越低,反之亦然。因此,锁的使用完全取决于逻辑。只有那些需要在同一时间内仅由一个线程运行且会发生变化的事物和位置才需要加锁。

如果您要对集合sub进行加锁,请使用较小的锁;但如果您要同时并行运行多个foreach循环,则需要使用更大的锁。


1

1

我认为有两个不同的问题:
1.哪一个是正确的?
2.哪一个会提供更好的性能?

正确性问题比较复杂。它取决于您的数据结构以及您打算如何使用锁来保护它们。如果“sub”对象不是线程安全的,则绝对需要大锁。

性能问题比较简单,但不太重要(但出于某种原因,我认为您更关注它)。
许多小锁可能会更慢,因为它们只是做更多的工作。但是,如果您成功地运行了循环代码的大部分而没有锁定,那么您就可以获得一些并发性,这将更好。


谢谢您的详细解释。我已经将使用非线程安全集合的循环放入锁中,就像我对包含集合修改的某些代码块所做的一样。这里大锁语句的问题是,该块还包含了一些来自同一类并使用相同同步对象的方法。因此,我认为有时会在运行程序时导致死锁(或者只是不需要的锁)。经过所有的修改后,程序现在更加响应迅速。 - 0x49D1

0

通过给定的代码片段,你无法有效地判断哪一个是“正确”的。第一个例子表示人们只看到来自交易所部分内容的订阅是不可以的。而第二个例子则表示人们只看到来自交易所部分内容的订阅是可以的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接