Verwendung einer threadsicheren AuflistungWhen to Use a Thread-Safe Collection

Mit .NET Framework 4.NET Framework 4 werden fünf neue Sammlungstypen eingeführt, die speziell für die Unterstützung von multithreaded Hinzufügen- und Entfernungsvorgängen ausgelegt sind.The .NET Framework 4.NET Framework 4 introduces five new collection types that are specially designed to support multi-threaded add and remove operations. Zur Gewährleistung von Threadsicherheit verwenden diese neuen Typen unterschiedliche Arten effizienter sperrender und sperrfreier Synchronisierungsmechanismen.To achieve thread-safety, these new types use various kinds of efficient locking and lock-free synchronization mechanisms. Ein Vorgang wird durch Synchronisierung aufwändiger.Synchronization adds overhead to an operation. Das Ausmaß des Aufwands hängt von der Art der verwendeten Synchronisierung, der Art der ausgeführten Vorgänge und von anderen Faktoren ab, z.B. der Anzahl der Threads, die versuchen, gleichzeitig auf die Sammlung zuzugreifen.The amount of overhead depends on the kind of synchronization that is used, the kind of operations that are performed, and other factors such as the number of threads that are trying to concurrently access the collection.

In einigen Szenarien ist der Synchronisierungsaufwand unwesentlich und ermöglicht eine deutlich schnellere Ausführung und bessere Skalierbarkeit des Multithreadtyps als beim nicht threadsicheren Äquivalent, wenn ein Schutz durch eine externe Sperre besteht.In some scenarios, synchronization overhead is negligible and enables the multi-threaded type to perform significantly faster and scale far better than its non-thread-safe equivalent when protected by an external lock. In anderen Szenarien kann der Aufwand dazu führen, dass der threadsichere Typ in etwa mit der gleichen oder sogar einer geringeren Leistung und Skalierbarkeit ausgeführt wird wie die extern gesperrte, nicht threadsichere Version des Typs.In other scenarios, the overhead can cause the thread-safe type to perform and scale about the same or even more slowly than the externally-locked, non-thread-safe version of the type.

Die folgenden Abschnitte enthalten eine allgemeine Anleitung dazu, wann eine threadsichere Sammlung anstelle ihres nicht threadsicheren Äquivalents verwendet wird, das eine vom Benutzer bereitgestellte Sperre für die Lese- und Schreibvorgänge besitzt.The following sections provide general guidance about when to use a thread-safe collection versus its non-thread-safe equivalent that has a user-provided lock around its read and write operations. Da die Leistung von vielen Faktoren abhängig sein kann, handelt es sich nicht um eine spezielle Anleitung, die daher nicht unter allen Umständen gültig ist.Because performance may vary depending on many factors, the guidance is not specific and is not necessarily valid in all circumstances. Wenn die Leistung sehr wichtig ist, ist die am besten geeignete Methode zur Bestimmung des zu verwendenden Sammlungstyps die Messung der Leistung auf Basis von repräsentativen Computerkonfigurationen und Lasten.If performance is very important, then the best way to determine which collection type to use is to measure performance based on representative computer configurations and loads. In diesem Dokument werden die folgenden Begriffe verwendet:This document uses the following terms:

Reines Producer-Consumer-SzenarioPure producer-consumer scenario
In jedem vorhandenen Thread werden Elemente entweder hinzugefügt oder entfernt, es finden jedoch nicht beide Vorgänge statt.Any given thread is either adding or removing elements, but not both.

Gemischtes Producer-Consumer-SzenarioMixed producer-consumer scenario
In jedem vorhandenen Thread werden Elemente sowohl hinzugefügt als auch entfernt.Any given thread is both adding and removing elements.

GeschwindigkeitszuwachsSpeedup
Höhere algorithmische Leistung relativ zu einem anderen Typ im gleichen Szenario.Faster algorithmic performance relative to another type in the same scenario.

SkalierbarkeitScalability
Die Zunahme der Leistung, die proportional zur Anzahl der Kerne des Computers ist.The increase in performance that is proportional to the number of cores on the computer. Mit einem Algorithmus, der skaliert wird, werden bei acht Kernen höhere Leistungen erzielt als bei zwei Kernen.An algorithm that scales performs faster on eight cores than it does on two cores.

ConcurrentQueue(T) oder Queue(T)ConcurrentQueue(T) vs. Queue(T)

In reinen Producer-Consumer-Szenarien, in denen die Verarbeitungszeit für jedes Element sehr kurz ist (einige Anweisungen), kann System.Collections.Concurrent.ConcurrentQueue<T> geringfügige Leistungsvorteile gegenüber System.Collections.Generic.Queue<T> mit einer externen Sperre bieten.In pure producer-consumer scenarios, where the processing time for each element is very small (a few instructions), then System.Collections.Concurrent.ConcurrentQueue<T> can offer modest performance benefits over a System.Collections.Generic.Queue<T> that has an external lock. In diesem Szenario erzielt ConcurrentQueue<T> die beste Leistung, wenn sich ein dedizierter Thread in der Warteschlange befindet und ein dedizierter Thread die Warteschlange verlässt.In this scenario, ConcurrentQueue<T> performs best when one dedicated thread is queuing and one dedicated thread is de-queuing. Wenn Sie diese Regel nicht erzwingen, kann Queue<T> sogar etwas schneller als ConcurrentQueue<T> auf Computern mit mehreren Kernen ausgeführt werden.If you do not enforce this rule, then Queue<T> might even perform slightly faster than ConcurrentQueue<T> on computers that have multiple cores.

Wenn die Verarbeitungszeit bei etwa 500 FLOPS (Gleitkommavorgänge) oder höher liegt, gilt die Zwei-Thread-Regel nicht für ConcurrentQueue<T>, sodass dann eine sehr gute Skalierbarkeit möglich ist.When processing time is around 500 FLOPS (floating point operations) or more, then the two-thread rule does not apply to ConcurrentQueue<T>, which then has very good scalability. Queue<T> lässt sich in diesem Szenario nicht vorteilhaft skalieren.Queue<T> does not scale well in this scenario.

Bei sehr geringer Verarbeitungszeit zeichnet sich Queue<T> mit einer externen Sperre in gemischten Producer-Consumer-Szenarien durch eine bessere Skalierbarkeit als ConcurrentQueue<T> aus.In mixed producer-consumer scenarios, when the processing time is very small, a Queue<T> that has an external lock scales better than ConcurrentQueue<T> does. Wenn die Verarbeitungszeit jedoch bei etwa 500 FLOPS oder darüber liegt, kann ConcurrentQueue<T> besser skaliert werden.However, when processing time is around 500 FLOPS or more, then the ConcurrentQueue<T> scales better.

ConcurrentStack oder StapelConcurrentStack vs. Stack

In reinen Producer-Consumer-Szenarien erzielen System.Collections.Concurrent.ConcurrentStack<T> und System.Collections.Generic.Stack<T> mit einer externen Sperre bei sehr geringer Verarbeitungszeit wahrscheinlich annähernd die gleiche Leistung mit einem dedizierten Thread für Ablegevorgänge und einem dedizierten Thread für Abholvorgänge.In pure producer-consumer scenarios, when processing time is very small, then System.Collections.Concurrent.ConcurrentStack<T> and System.Collections.Generic.Stack<T> that has an external lock will probably perform about the same with one dedicated pushing thread and one dedicated popping thread. Bei zunehmender Anzahl der Threads werden jedoch beide Typen aufgrund des stärkeren Konflikts langsamer, und mit Stack<T> werden unter Umständen bessere Leistungen als mit ConcurrentStack<T> erzielt.However, as the number of threads increases, both types slow down because of increased contention, and Stack<T> might perform better than ConcurrentStack<T>. Wenn die Verarbeitungszeit bei rund 500 FLOPS oder darüber liegt, werden beide Typen mit der etwa gleichen Rate skaliert.When processing time is around 500 FLOPS or more, then both types scale at about the same rate.

In gemischten Producer-Consumer-Szenarien ist ConcurrentStack<T> für kleine und große Arbeitsauslastungen schneller.In mixed producer-consumer scenarios, ConcurrentStack<T> is faster for both small and large workloads.

Die Verwendung von PushRange und TryPopRange kann die Zugriffszeiten unter Umständen erheblich beschleunigen.The use of the PushRange and TryPopRange may greatly speed up access times.

ConcurrentDictionary oder DictionaryConcurrentDictionary vs. Dictionary

Verwenden Sie System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> im Allgemeinen in jedem Szenario, in dem Sie Schlüssel oder Werte gleichzeitig aus mehreren Threads hinzufügen und aktualisieren.In general, use a System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> in any scenario where you are adding and updating keys or values concurrently from multiple threads. In Szenarien, die häufige Updates und relativ wenige Lesevorgänge umfassen, bietet ConcurrentDictionary<TKey,TValue> in der Regel geringfügige Vorteile.In scenarios that involve frequent updates and relatively few reads, the ConcurrentDictionary<TKey,TValue> generally offers modest benefits. In Szenarien, die zahlreiche Lesevorgänge und Updates umfassen, ist ConcurrentDictionary<TKey,TValue> im Allgemeinen auf Computern bedeutend schneller, die über eine beliebige Anzahl von Kernen verfügen.In scenarios that involve many reads and many updates, the ConcurrentDictionary<TKey,TValue> generally is significantly faster on computers that have any number of cores.

In Szenarien, die häufige Updates umfassen, können Sie den Grad der Parallelität in ConcurrentDictionary<TKey,TValue> erhöhen und anschließend ermitteln, ob sich die Leistung auf Computern mit einer größeren Anzahl von Kernen verbessert.In scenarios that involve frequent updates, you can increase the degree of concurrency in the ConcurrentDictionary<TKey,TValue> and then measure to see whether performance increases on computers that have more cores. Wenn Sie die Parallelitätsebene ändern, vermeiden Sie so weit wie möglich globale Vorgänge.If you change the concurrency level, avoid global operations as much as possible.

Wenn Sie nur Schlüssel oder Werte lesen, ist Dictionary<TKey,TValue> schneller, da keine Synchronisierung erforderlich ist, wenn das Wörterbuch nicht von Threads geändert wird.If you are only reading key or values, the Dictionary<TKey,TValue> is faster because no synchronization is required if the dictionary is not being modified by any threads.

ConcurrentBagConcurrentBag

In reinen Producer-Consumer-Szenarien ist System.Collections.Concurrent.ConcurrentBag<T> wahrscheinlich langsamer als die anderen gleichzeitigen Sammlungstypen.In pure producer-consumer scenarios, System.Collections.Concurrent.ConcurrentBag<T> will probably perform more slowly than the other concurrent collection types.

In gemischten Producer-Consumer-Szenarien ist ConcurrentBag<T> sowohl bei großen als auch bei kleinen Arbeitsauslastungen im Allgemeinen viel schneller und besser skalierbar als ein beliebiger anderer gleichzeitiger Sammlungstyp.In mixed producer-consumer scenarios, ConcurrentBag<T> is generally much faster and more scalable than any other concurrent collection type for both large and small workloads.

BlockingCollectionBlockingCollection

Wenn Begrenzungs- und Blockierungssemantiken erforderlich sind, wird System.Collections.Concurrent.BlockingCollection<T> wahrscheinlich schneller als jede beliebige benutzerdefinierte Implementierung ausgeführt.When bounding and blocking semantics are required, System.Collections.Concurrent.BlockingCollection<T> will probably perform faster than any custom implementation. Zudem werden umfassende Möglichkeiten für die Abbruch-, Enumerations- und Ausnahmebehandlung unterstützt.It also supports rich cancellation, enumeration, and exception handling.

Siehe auchSee Also

System.Collections.Concurrent
threadsichere AuflistungenThread-Safe Collections
Parallele ProgrammierungParallel Programming