2

所以,我有一个Dictionary<KType,VType> Foo

在一个线程中,我有:

void Thread1() {
  ...
  if (!Foo.TryGetValue(key, out v)) {
    Foo.Add(new VType());
  }
  ...
}

唯一一次Foo被另一个线程访问的是TryGetValue.

那么,我需要锁定多少钱?我可以做类似的事情:

void Thread1() {
  ...
  if (!Foo.TryGetValue(key, out v)) {
    lock (syncobj) {
      Foo.Add(new VType());
    }
  }
  ...
}
void Thread2() {
  ...
  lock (syncobj) {
    Foo.TryGetValue(key, out v))
  }
  ...
}

Thread1 占程序计算的 90%,并被TryGetValue多次调用。因此,最好不要每次都调用 lock 。

4

1 回答 1

7

如果在执行 a 的同时有可能在另一个线程上发生更新,则lock每次都必须这样做。TryGetValue

TryGetValue本身是线程安全的,因为多个线程调用TryGetValue不会相互干扰。但是,如果任何线程调用Add而其他人正在对字典做任何其他事情,那么就有可能发生损坏。

也就是说,锁可能并不可怕。你说这TryGetValue叫做“很多次”,但你没有说多久一次。更重要的是,你没有说你可能多久发生一次冲突。在现代硬件上,一个无竞争的锁会花费你大约 50 纳秒的时间,所以这并不是一笔巨大的开支。您可能会尝试锁定只是为了看看它是如何执行的。您也可以考虑使用ReaderWriterLockSlim

重要的是要了解这ConcurrentDictionary不是无锁数据结构,尽管读取操作是以无锁方式完成的。它可能在您的情况下表现更好(可能会),但这不是给定的。

于 2013-06-05T00:02:21.417 回答