Datenstrukturen für die parallele Programmierung
.NET stellt mehrere Typen bereit, die für die parallele Programmierung nützlich sind. Darunter befinden sich eine Reihe von parallelen Auflistungsklassen, einfache Synchronisierungsprimitive und Typen für die verzögerte Initialisierung. Sie können diese Typen mit jedem Multithreadanwendungscode verwenden, einschließlich der Task Parallel Library und PLINQ.
Parallele Auflistungsklassen
Die Auflistungsklassen im Namespace System.Collections.Concurrent bieten threadsichere Vorgänge für das Hinzufügen und Entfernen. Diese vermeiden Sperren, wo immer dies möglich ist, und setzen differenzierte Sperren ein, wenn Sperren erforderlich sind. Eine parallele Auflistungsklasse benötigt beim Zugriff auf Elemente keinen Benutzercode für Sperren. Die parallelen Auflistungsklassen können die Leistung gegenüber Typen wie System.Collections.ArrayList und System.Collections.Generic.List<T> (mit benutzerimplementierter Sperre) in Szenarien, in denen mehrere Threads Elemente aus einer Auflistung hinzufügen und entfernen, erheblich verbessern.
In der folgenden Tabelle sind die parallelen Auflistungsklassen aufgeführt:
Geben Sie Folgendes ein: | Beschreibung |
---|---|
System.Collections.Concurrent.BlockingCollection<T> | Stellt Sperr- und Begrenzungsfunktionen für threadsichere Auflistungen bereit, die System.Collections.Concurrent.IProducerConsumerCollection<T> implementieren. Producerthreads werden blockiert, wenn keine Zeitfenster verfügbar sind oder wenn die Auflistung voll ist. Consumerthreads werden blockiert, wenn die Auflistung leer ist. Dieser Typ unterstützt auch nicht blockierenden Zugriff durch Consumer und Producer. BlockingCollection<T> kann als Basisklasse oder Sicherungsspeicher verwendet werden, um das Blockieren und Binden für jede Auflistungsklasse zu ermöglichen, die IEnumerable<T> unterstützt. |
System.Collections.Concurrent.ConcurrentBag<T> | Eine threadsichere Behälterimplementierung, die skalierbare Vorgänge zum Hinzufügen und Abrufen bietet. |
System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> | Ein paralleler und skalierbarer Wörterbuchtyp |
System.Collections.Concurrent.ConcurrentQueue<T> | Eine parallele und skalierbare FIFO-Warteschlange |
System.Collections.Concurrent.ConcurrentStack<T> | Ein paralleler und skalierbarer LIFO-Stapel |
Weitere Informationen finden Sie unter Threadsichere Auflistungen.
Synchronisierungsprimitiven
Die Synchronisierungsprimitiven im System.Threading-Namespace ermöglichen eine differenzierte Parallelität und schnellere Leistung durch das Vermeiden ressourcenintensiver Sperrmechanismen in Legacy-Multithreadingcode.
Die folgende Tabelle enthält die Synchronisierungstypen:
type | BESCHREIBUNG |
---|---|
System.Threading.Barrier | Ermöglicht mehreren Threads, parallel an einem Algorithmus zu arbeiten, indem ein Punkt bereitgestellt wird, an dem jeder Task seine Ankunft signalisieren und dann blockieren kann, bis einige oder alle Tasks angekommen sind. Weitere Informationen finden Sie unter Barrier. |
System.Threading.CountdownEvent | Vereinfacht Fork- und Join-Szenarien durch einen einfachen Rendezvousmechanismus. Weitere Informationen finden Sie unter CountdownEvent. |
System.Threading.ManualResetEventSlim | Eine Synchronisierungsprimitive, ähnlich wie System.Threading.ManualResetEvent. ManualResetEventSlim ist einfacher, kann aber nur für prozessinterne Kommunikation verwendet werden. |
System.Threading.SemaphoreSlim | Eine Synchronisierungsprimitive, die die Anzahl von Threads beschränkt, die parallel auf eine Ressource oder einen Ressourcenpool zugreifen können. Weitere Informationen finden Sie unter Semaphore und SemaphoreSlim. |
System.Threading.SpinLock | Eine gegenseitige Ausschlusssperrprimitive, durch die der Thread, der die Sperre zu erlangen versucht, für eine gewisse Zeit in einer Schleife warten (oder rotieren) muss, bevor er sein Quantum liefert. In Szenarien, in denen die Wartezeit für die Sperre nur kurz ist, bietet SpinLock eine bessere Leistung als andere Arten von Sperren. Weitere Informationen finden Sie unter SpinLock. |
System.Threading.SpinWait | Ein kleiner, einfacher Typ, der für eine bestimmte Zeit rotiert und schließlich den Thread in einen Wartezustand versetzt, wenn die Schleifenzahl überschritten wird. Weitere Informationen finden Sie unter SpinWait. |
Weitere Informationen finden Sie unter
Gewusst wie: Synchronisierung auf niedriger Ebene mit SpinLock
Vorgehensweise: Synchronisieren gleichzeitiger Vorgänge mit einer Barriere.
Klassen mit verzögerter Initialisierung
Bei einer verzögerten Initialisierung wird der Speicher für ein Objekt nicht zugewiesen, bis dieser benötigt wird. Eine verzögerte Initialisierung kann zur Verbesserung der Leistung beitragen, indem Objektzuweisungen über die Lebensdauer eines Programms hinweg verteilt werden. Sie können die verzögerte Initialisierung für jeden benutzerdefinierten Typ verwenden, indem Sie damit den Typ Lazy<T> umschließen.
Die folgende Tabelle enthält eine Auflistung der Typen für eine verzögerte Initialisierung:
type | BESCHREIBUNG |
---|---|
System.Lazy<T> | Stellt einfache, threadsichere verzögerte Initialisierung bereit. |
System.Threading.ThreadLocal<T> | Stellt einen Wert durch eine verzögerte Initialisierung auf Threadbasis bereit, wobei jeder Thread die Initialisierungsfunktion verzögert aufruft. |
System.Threading.LazyInitializer | Stellt statische Methoden bereit, durch die das Zuweisen einer dedizierten Instanz für die verzögerte Initialisierung nicht mehr erforderlich ist. Stattdessen werden Verweise eingesetzt, um sicherzustellen, dass Ziele initialisiert werden, sobald darauf zugegriffen wird. |
Weitere Informationen finden Sie unter Verzögerte Initialisierung.
Aggregieren von Ausnahmen
Die System.AggregateException-Typ kann verwendet werden, um mehrere Ausnahmen zu erfassen, die in separaten Threads parallel ausgelöst und an den Verbindungsthread als eine einzelne Ausnahme zurückgegeben werden. Die Typen System.Threading.Tasks.Task und System.Threading.Tasks.Parallel sowie PLINQ verwenden hierzu sehr häufig AggregateException. Weitere Informationen finden Sie unter Ausnahmebehandlung und unter Vorgehensweise: Behandeln von Ausnahmen in einer PLINQ-Abfrage.