2009-08-06 4 views
2

Ich habe eine Multi-Thread-C# -Anwendung. Es gibt ein Wörterbuch, auf das von N verschiedenen Threads zur gleichen Zeit zugegriffen wird. 99% der Anrufe sind von Thread A und der Rest ist von B, C, ...C# Threading-Leistung, ein Thread 99% der Zeit

Im Moment schließe ich nur das Wörterbuch bei jedem Zugriff. Aber es scheint verschwenderisch, denn 99% der Zeit, die ich anrufe, sperren, Thread A hat bereits das Schloss.

Was wäre ein effizienterer Weg dies zu tun?

Vielleicht eine Art .Begin und .End-Aufrufe könnten für die Threads B, C, ... erforderlich sein, und dann müsste Thread A bei jedem Aufruf nur ein Bit prüfen, um festzustellen, ob einer der anderen Threads verwendet wird das Wörterbuch. Hat jemand ein Codebeispiel von sowas threadsicher implementiert?

+0

Siehe auch http://stackoverflow.com/questions/157933/whats-the-best-way-of-implementing-a mit -thread-safe-dictionary-in-net –

Antwort

4

Sie müssen Ihre Profilerdaten sorgfältig prüfen.

Sowohl Monitor als auch RWLSlim werden nicht wirklich "hard-lock" (wie in Dropdown auf die OS-Grundelemente), es sei denn, es gibt eine tatsächliche Konkurrenz; In allen anderen Fällen wird Interlocked verwendet, und die Auswirkungen sind relativ gering (abgesehen von den Cache-Flushes).

Leistungsmäßig ist RWLockSlim relativ teuer zu erstellen und ein wenig teurer als Monitor zu betreten. Seine Tugend ist es, mehrere Leser und einen einzigen Schriftsteller zu erlauben.

Wenn Hardlocks angezeigt werden, haben Sie eine tatsächliche Konkurrenzsituation. In diesem Fall spiegelt das von Ihnen angegebene Verhältnis von 99%/1%/1%/1%/... wahrscheinlich nicht die Realität wider.

Wie vorherige Plakate angemerkt, sollten Sie tha Patten der Verwendung - in den meisten Fällen haben Sie gelegentliche Schreibvorgänge und massive Lesevorgänge, sonst ist die Konsistenz des Systems ein wenig schwierig zu erzwingen. Wenn dies der Fall ist, sollte RWlockSlim unnötige Konflikte entfernen.

Bottomline: Es hängt alles davon ab, was Sie versuchen zu tun - wie in dem, was dieses Wörterbuch ist und wie zugegriffen wird. Manchmal macht es Sinn, Locks zu verbreitern, um zu viele davon zu vermeiden, und in einigen - sehr seltenen - Fällen möchten Sie vielleicht mit Lock-Free-Style-Primitiven wie Interlocked spielen, bevor Sie überhaupt versuchen, die "echte" Sperre zu treffen.

Vielleicht könnten Sie uns, wenn Sie uns mehr über das Szenario erzählen, besser helfen.

2

Wie führen Sie die Sperre durch? Zum Lesen müssen Sie die anderen Threads nicht auf die gleiche "harte" Art und Weise sperren, als ob Sie gerade updaten würden. In beiden Fällen können Sie bei den Lesevorgängen etwas lockerer sein. Ich würde vorschlagen, die ReaderWriterLockSlim Blick in (es sei denn Sie es bereits verwenden):

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(); 
     } 
    } 
} 

Dies wird mehrere Threads ermöglichen, aus dem Wörterbuch „zur gleichen Zeit“ zu lesen, während der Zugriff von anderen Threads blockieren, wenn es aktualisiert wird.

+0

Danke, ich habe über den ReaderWriterLockSlim nachgedacht. Irgendeine Idee, wie die Perf von "_lock.EnterReadLock()" mit "Monitor.Enter" verglichen wird? Ich habe es noch nie zuvor benutzt. –

+0

Ich kann die Leistung des Erlangens des Schlosses als solches nicht kommentieren, aber die Oberseite mit '_lock.EnterReadLock' ist, das andere Threads nicht ausschließt, die auch eine Leserverriegelung wünschen. Es gibt nur um den Update-Vorgang (geschützt durch die '_lock.EnterReadLock'), dass Sie eine Sperre haben, die anderen Threads den Zugriff auf das Wörterbuch blockieren wird. –

2

Sie sollten sich keine Sorgen machen, es sei denn, ein Profiler sagt Ihnen, dass Sie viel Zeit in Monitor.Enter und Unternehmen verbringen - im Allgemeinen eine sehr schnelle Operation und sollte eine unbeschränkte Sperre oder eine Sperre erhalten in der Leistung der Bitprüfung ähnlich sein, die Sie vorschlagen. Eine Sperroperation ist normalerweise nur langsam, wenn sie aufgrund von Konflikten blockiert werden muss.

+0

Danke. Laut dem ANTS-Profiler nimmt der Lock-Call leider einen großen Teil der Zeit in Anspruch, die ich in der Funktion verbringe. –

1

ReaderWriterLockSlim hilft, wenn es viele Leser und wenige Autoren gibt. Die individuelle Betriebsleistung von ReaderWriterLockSlim schien jedoch schlechter zu sein als die von Monitor gemäß folgendem Link: A Performance Comparison of ReaderWriterLockSlim with ReaderWriterLock.

Eine Option, die Sie ausprobieren können, besteht darin, mit Interlocked-Operationen zusammen mit Event-Objekten zu spielen, um Threads zu synchronisieren. Aber auch hier sollten Sie die Leistung dieses Ansatzes messen.

0

Versuchen System.Collections.Concurrent.ConcurrentDictionary in .NET 4,0

Es ist Thread-sicher nach Design

+0

Das ist eine gute Option von .NET 4. Wissen Sie, wie es implementiert wird? Ich frage mich, wie es funktioniert vs nur Sperren aller Zugriffe auf ein normales Wörterbuch. –

+1

System.Collections.Concurrent-Mitglieder sind in Thread-sicher integriert. Nichts besonderes zu tun. Verwenden Sie z. B. die Warteschlange "Gleichzeitige" mit mehreren Threads und rufen Sie ohne weitere Überlegungen "Enqueue" oder "Dequeue" auf. Wenn Sie Details benötigen, verwenden Sie Reflector für die gewünschte Bibliothek zur Implementierung. Nach meiner Erfahrung ist die Geschwindigkeit gut. – Xaqron