Freigeben über


Threadsichere Auflistungen

Das .NET Framework 4 führt den System.Collections.Concurrent-Namespace ein, der mehrere Auflistungsklassen einschließt, die sowohl threadsicher als auch skalierbar sind. Mehrere Threads können diesen Auflistungen sicher und effizient Elemente hinzufügen bzw. daraus entfernen, ohne dass zusätzliche Synchronisierung in Benutzercode erforderlich ist. Wenn Sie neuen Code schreiben, verwenden Sie immer dann die Klassen für parallele Auflistungsvorgänge, wenn mehrere Threads gleichzeitig Schreibvorgänge in der Auflistung ausführen. Wenn Sie nur von einer freigegebenen Auflistung lesen, können Sie die Klassen im System.Collections.Generic-Namespace verwenden. Es wird empfohlen, keine 1.0-Auflistungsklassen zu verwenden, sofern als Zielversion nicht .NET Framework 1.1 oder eine frühere Laufzeit festgelegt wird.

Threadsynchronisierung in den Auflistungen von .NET Framework 1.0 und 2.0

Die in .NET Framework 1.0 eingeführten Auflistungen befinden sich im System.Collections-Namespace. Diese Auflistungen, die das häufig verwendete ArrayList-Objekt und das Hashtable-Objekt einschließen, bieten eine gewisse Threadsicherheit durch die Synchronized-Eigenschaft, von der ein threadsicherer Wrapper um die Auflistung zurückgegeben wird. Der Wrapper funktioniert folgendermaßen: Die gesamte Auflistung wird bei jedem Hinzufüge- oder Entfernungsvorgang gesperrt. Daher muss jeder Thread, der versucht, auf die Auflistung zuzugreifen, warten, bis er die jeweilige Sperre übernehmen kann. Dies ist nicht skalierbar und kann beträchtliche Leistungseinbußen für große Auflistungen verursachen. Außerdem wird der Entwurf nicht völlig vor Racebedingungen geschützt. Weitere Informationen finden Sie im Blogbeitrag Synchronization in Generic Collections (Synchronisierung in generischen Auflistungen).

Die in .NET Framework 2.0 eingeführten Auflistungsklassen befinden sich im System.Collections.Generic-Namespace. Dazu gehören List<T>, Dictionary<TKey,TValue> usw. Diese Klassen bieten verbesserte Typsicherheit und Leistung im Vergleich zu den .NET Framework 1.0-Klassen. Die .NET Framework 2.0-Auflistungsklassen stellen jedoch keine Threadsynchronisierung bereit; Benutzercode muss die gesamte Synchronisierung bereitstellen, wenn Elemente gleichzeitig in mehreren Threads hinzugefügt oder entfernt werden.

Es wird empfohlen, die gleichzeitigen Auflistungsklassen im .NET Framework 4 zu verwenden, da sie nicht nur die Typsicherheit der .NET Framework 2.0-Auflistungsklassen, sondern auch eine effizientere und vollständigere Threadsicherheit als die Auflistungen von .NET Framework 1.0 bieten.

Differenzierte Sperre und sperrenfreie Mechanismen

Einige der gleichzeitigen Auflistungstypen verwenden einfache Synchronisierungsmechanismen, z. B. SpinLock, SpinWait, SemaphoreSlim, und CountdownEvent, die neu im .NET Framework 4 sind. Diese Synchronisierungstypen verwenden normalerweise andauernde Spinvorgänge für die kurzen Zeiträume, bevor der Thread in einen echten Wartezustand versetzt wird. Wenn Wartezeiten als sehr kurz eingeschätzt werden, sind Spinvorgänge weitaus weniger rechenintensiv als Wartezustände, die einen aufwändigen Kernel-Übergang umfassen. Für Auflistungsklassen, für die Spinvorgänge verwendet werden, bedeutet diese Effizienz, dass mehrere Threads Elemente mit einer sehr hohen Rate hinzufügen und entfernen können. Weitere Informationen zu Spinvorgängen im Vergleich zu Blockierungen finden Sie unter SpinLock und SpinWait.

Für die ConcurrentQueue<T>-Klasse und die ConcurrentStack<T>-Klasse werden gar keine Sperren verwendet. Stattdessen wird die Threadsicherheit durch Interlocked-Vorgänge gewährleistet.

Hinweis

Da die gleichzeitigen Auflistungsklassen ICollection unterstützen, stellen sie Implementierungen für die IsSynchronized-Eigenschaft und die SyncRoot-Eigenschaft bereit, auch wenn diese Eigenschaften nicht relevant sind. IsSynchronized gibt immer false zurück, und SyncRoot ist immer null (Nothing in Visual Basic).

In der folgenden Tabelle sind die Auflistungstypen im System.Collections.Concurrent-Namespace aufgeführt.

Typ Beschreibung
BlockingCollection<T> Stellt Begrenzungs- und Blockierungsfunktionen für jeden Typ bereit, von dem IProducerConsumerCollection<T> implementiert wird. Weitere Informationen finden Sie unter Übersicht über BlockingCollection.
ConcurrentDictionary<TKey,TValue> Threadsichere Implementierung eines Wörterbuchs von Schlüssel-Wert-Paaren.
ConcurrentQueue<T> Threadsichere Implementierung einer First In, First Out (FIFO)-Warteschlange.
ConcurrentStack<T> Threadsichere Implementierung eines Last In, First Out (LIFO)-Stapels.
ConcurrentBag<T> Threadsichere Implementierung einer ungeordneten Auflistung von Elementen.
IProducerConsumerCollection<T> Die Schnittstelle, die ein Typ implementieren muss, damit sie in BlockingCollection verwendet werden kann.
Titel Beschreibung
Übersicht über BlockingCollection Beschreibt die vom BlockingCollection<T>-Typ bereitgestellte Funktion.
How to: Hinzufügen und Entfernen von Elementen aus einem ConcurrentDictionary Beschreibt, wie Elemente aus einem ConcurrentDictionary<TKey,TValue>-Objekt hinzugefügt und entfernt werden.
How to: Hinzufügen und Entfernen von einzelnen Elementen zu bzw. aus einer BlockingCollection Beschreibt, wie Elemente einer Blockierungsauflistung hinzugefügt und daraus abgerufen werden, ohne dass der schreibgeschützte Enumerator verwendet wird.
How to: Hinzufügen von Begrenzungs- und Blockierungsfunktionen zu einer Auflistung Beschreibt, wie jede Auflistungsklasse als zugrunde liegender Speichermechanismus für eine IProducerConsumerCollection<T>-Auflistung verwendet wird.
How to: Verwenden von ForEach zum Entfernen von Elementen aus einer BlockingCollection Beschreibt, wie mit einer foreach-Anweisung (For Each in Visual Basic) alle Elemente in einer Blockierungsauflistung entfernt werden.
How to: Verwenden von Arrays mit blockierenden Auflistungen in einer Pipeline Beschreibt, wie mit mehreren Blockierungsauflistungen gleichzeitig eine Pipeline implementiert wird.
How to: Erstellen eines Objektpools mit ConcurrentBag Zeigt die Verwendung einer parallelen Sammlung zur Verbesserung der Leistung in Szenarien, in denen Sie Objekte nicht fortlaufend neu erstellen müssen, sondern diese wiederverwenden können.

Referenz

System.Collections.Concurrent