2009-08-06 59 views
2

我有一个多线程的C#应用​​程序。有一个字典可以同时从N个不同的线程访问。来电的99%都来自线程A,其余都是从B,C,...C#线程性能,一线程99%的时间

现在,我只是锁定在每次访问字典。但它看起来很浪费,因为99%的时间我叫锁,线程A已经锁定。

这样做会更有效吗?

也许某些类型的.Begin和.End调用可能需要线程B,C ...,然后线程A只需检查每个调用中的一个位以查看是否有其他线程正在使用词典。有没有人有这样的线程安全的方式实现的代码示例?

+0

参见http://stackoverflow.com/questions/157933/whats-the-best-way-of-implementing-a -thread-safe-dictionary-in-net – 2009-08-06 20:30:46

回答

4

您需要仔细检查您的分析器数据。

两个监视器和RWLSlim不会真正“硬锁”(如在下拉到OS原语),除非有一个实际的竞争;在所有其他情况下将使用Interlocked,并且相对最小的性能影响(除缓存刷新外)。

性能方面,RWLockSlim的创建成本相对较高,而且比Monitor要贵一些。它的优点是允许多个读者和一个作家。

如果您看到硬盘锁显示出来,那么你有实际的竞争,在这种情况下,你可能说99%/ 1%/ 1%/ 1%/ ...比率不能反映现实。

正如前面提到的海报,你应该exmaine使用的塔彭定康 - 在大多数情况下,你偶尔也会写入和读取大量,否则系统的一致性有些难以enforfce。如果是这种情况,RWlockSlim应该消除不必要的争用。

底线:这一切都取决于你正在尝试做的事情 - 在什么这本字典是如何被访问。有时候扩展锁以防止占用过多的锁是有意义的,而在某些情况下(甚至非常罕见),在尝试击中“真正”锁之前,您可能需要使用“无锁”类型的无锁基元。

也许如果你告诉了我们更多关于这个场景的信息,我们可以帮助更好。

2

你如何执行锁定。对于阅读而言,您不需要像“更新”一样以“硬”的方式锁定其他线索。无论哪种方式,读取操作都会变得更松散。我建议寻找到ReaderWriterLockSlim(除非你已经在使用它):

class DictionaryHolder 
{ 
    private IDictionary<int, string> _data = new Dictionary<int, string>(); 
    private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); 
    public void Update(int key, string value) 
    { 
     _lock.EnterWriteLock();    
     try 
     { 
      _data[key] = value; 
     } 
     finally 
     { 
      _lock.ExitWriteLock(); 
     } 
    } 

    public string GetValue(int key) 
    { 
     _lock.EnterReadLock(); 
     try 
     { 
      if (_data.ContainsKey(key)) 
      { 
       return _data[key]; 
     } 
     finally 
     { 
      _lock.ExitReadLock(); 
     } 
    } 
} 

这将允许多个线程从字典“在同一时间”阅读,在更新时,它阻止来自其他线程访问。

+0

谢谢,我在考虑ReaderWriterLockSlim。任何想法如何将“_lock.EnterReadLock()”的性能与“Monitor.Enter”进行比较?我从来没有用过它。 – 2009-08-06 20:45:12

+0

我无法对获取锁的性能发表评论,但'_lock.EnterReadLock'的优势在于不会锁定其他线程也需要读者锁定。它只是在更新操作的周围(由'_lock.EnterReadLock'保护),你有一个锁会阻止其他线程访问字典。 – 2009-08-06 20:53:39

2

你不应该担心这个,除非分析器告诉你,你是花了很多的Monitor.Enter和公司的时间 - 在一般情况下,获得你已经持有非竞争锁或锁是一个非常快的操作,必须性能与您建议的位检查类似。锁定操作通常只有在由于争用而必须阻止时才会很慢。

+0

谢谢。不幸的是,根据ANTS分析器,锁定呼叫占用了我在该函数中花费的大部分时间。 – 2009-08-06 20:47:28

1

ReaderWriterLockSlim在有很多读者和很少的作者时会有所帮助。但是,根据以下链接,ReaderWriterLockSlim的个人操作性能似乎比Monitor差:A Performance Comparison of ReaderWriterLockSlim with ReaderWriterLock

你可以尝试的一个选择是与Interlocked操作一起玩Event对象来同步线程。但是,你也应该测量这种方法的性能。

0

尝试在.NET中使用System.Collections.Concurrent.ConcurrentDictionary 4.0

这是线程安全的设计

+0

这是.NET 4的一个很好的选择。你知道它的实现吗?我想知道它是如何执行的,而不是锁定对常规字典的所有访问。 – 2010-10-05 12:59:54

+1

System.Collections.Concurrent成员是内置线程安全的。没什么特别的。例如,使用带有多个线程的并发队列,并且无需考虑任何事情就调用'Enqueue'或'Dequeue'。如果您想了解详细信息,请在所需的库上使用Reflector来实现。根据我的经验,速度很好。 – Xaqron 2010-10-05 17:24:05