2009-08-06 57 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