Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
BlockingCollection<T> ist eine threadsichere Sammlungsklasse, die die folgenden Features bereitstellt:
Implementierung des Producer-Consumer-Musters.
Gleichzeitiges Hinzufügen und Übernehmen von Elementen aus mehreren Threads.
Optionale maximale Kapazität.
Einfüge- und Löschvorgänge, die blockiert werden, wenn die Sammlung leer oder voll ist.
Einfüge- und Löschvorgänge zum „Ausprobieren“, die Abläufe nicht oder nur für eine festgelegte Zeitspanne blockieren.
Kapselt jeden Sammlungstyp, der IProducerConsumerCollection<T> implementiert.
Abbruch mit Abbruchtoken.
Zwei Arten von Aufzählung mit
foreach
(For Each
in Visual Basic):Schreibgeschützte Enumeration.
Enumeration, in deren Verlauf Elemente entfernt werden.
Unterstützung von Begrenzen und Blockieren
BlockingCollection<T> unterstützt das Begrenzen und Blockieren. Begrenzen bedeutet, dass Sie die maximale Kapazität der Sammlung festlegen können. Das Begrenzen ist in bestimmten Szenarien wichtig, da es Ihnen ermöglicht, die maximale Größe der Sammlung im Arbeitsspeicher zu steuern, und es verhindert, dass die erzeugenden Threads den verbrauchenden Threads zu weit vorauseilen.
Mehrere Threads oder Tasks können gleichzeitig der Sammlung Elemente hinzufügen, und wenn die Sammlung die angegebene maximale Kapazität erreicht, werden die erzeugenden Threads blockiert, bis ein Element entfernt wird. Mehrere Verbraucher können Elemente gleichzeitig entfernen, und wenn die Sammlung leer wird, blockieren die verbrauchenden Threads, bis ein Produzent ein Element hinzufügt. Ein produzierender Thread kann CompleteAdding aufrufen, um anzugeben, dass keine weiteren Elemente hinzugefügt werden. Verbraucher überwachen die IsCompleted Eigenschaft, um zu wissen, wann die Sammlung leer ist und keine weiteren Elemente hinzugefügt werden. Das folgende Beispiel zeigt eine einfache BlockingCollection mit einer begrenzten Kapazität von 100. Ein Producertask fügt der Sammlung Elemente hinzu, solange eine externe Bedingung wahr ist, und ruft dann CompleteAdding auf. Der Consumertask entnimmt Elemente, bis die IsCompleted-Eigenschaft wahr ist.
// A bounded collection. It can hold no more
// than 100 items at once.
BlockingCollection<Data> dataItems = new BlockingCollection<Data>(100);
// A simple blocking consumer with no cancellation.
Task.Run(() =>
{
while (!dataItems.IsCompleted)
{
Data data = null;
// Blocks if dataItems.Count == 0.
// IOE means that Take() was called on a completed collection.
// Some other thread can call CompleteAdding after we pass the
// IsCompleted check but before we call Take.
// In this example, we can simply catch the exception since the
// loop will break on the next iteration.
try
{
data = dataItems.Take();
}
catch (InvalidOperationException) { }
if (data != null)
{
Process(data);
}
}
Console.WriteLine("\r\nNo more items to take.");
});
// A simple blocking producer with no cancellation.
Task.Run(() =>
{
while (moreItemsToAdd)
{
Data data = GetData();
// Blocks if numbers.Count == dataItems.BoundedCapacity
dataItems.Add(data);
}
// Let consumer know we are done.
dataItems.CompleteAdding();
});
' A bounded collection. It can hold no more
' than 100 items at once.
Dim dataItems = New BlockingCollection(Of Data)(100)
' A simple blocking consumer with no cancellation.
Task.Factory.StartNew(Sub()
While dataItems.IsCompleted = False
Dim dataItem As Data = Nothing
Try
dataItem = dataItems.Take()
Catch e As InvalidOperationException
' IOE means that Take() was called on a completed collection.
' In this example, we can simply catch the exception since the
' loop will break on the next iteration.
End Try
If (dataItem IsNot Nothing) Then
Process(dataItem)
End If
End While
Console.WriteLine(vbCrLf & "No more items to take.")
End Sub)
' A simple blocking producer with no cancellation.
Task.Factory.StartNew(Sub()
While moreItemsToAdd = True
Dim item As Data = GetData()
' Blocks if dataItems.Count = dataItems.BoundedCapacity.
dataItems.Add(item)
End While
' Let consumer know we are done.
dataItems.CompleteAdding()
End Sub)
Ein vollständiges Beispiel finden Sie unter Anleitung: Elemente einzeln zu einer BlockingCollection hinzufügen und entnehmen.
Zeitgesteuerte Blockiervorgänge
In zeitgesteuerten TryAdd- und TryTake-Blockierungsvorgängen, die für begrenzte Sammlungen durchgeführt werden, versucht die Methode, ein Element hinzuzufügen oder zu entnehmen. Wenn ein Element verfügbar ist, wird es in die Variable eingefügt, die per Verweis übergeben wurde, und die Methode gibt "true" zurück. Wenn nach einem angegebenen Timeoutzeitraum kein Element abgerufen wird, gibt die Methode "false" zurück. Der Thread kann dann andere nützliche Aufgaben ausführen, bevor er erneut versucht, auf die Sammlung zuzugreifen. Ein Beispiel für ein zeitgesteuertes Blockieren des Zugriffs finden Sie im zweiten Beispiel unter Vorgehensweise: Hinzufügen und Entfernen von einzelnen Elementen zu bzw. aus einer BlockingCollection.
Abbrechen von Hinzufüge- und Entnahmevorgängen
Hinzufüge- und Entnahmevorgänge werden in der Regel in einer Schleife ausgeführt. Sie können eine Schleife durch die Übergabe eines CancellationToken an die TryAdd- oder TryTake-Methode abbrechen und dann den Wert der IsCancellationRequested-Eigenschaft des Tokens in jeder Iteration überprüfen. Wenn der Wert "true" ist, liegt es an Ihnen, auf die Abbruchanforderung zu antworten, indem Sie alle Ressourcen bereinigen und die Schleife beenden. Das folgende Beispiel zeigt eine Überladung von TryAdd, die ein Abbruchtoken entgegennimmt, und den Code, der es verwendet:
do
{
// Cancellation causes OCE. We know how to handle it.
try
{
success = bc.TryAdd(itemToAdd, 2, ct);
}
catch (OperationCanceledException)
{
bc.CompleteAdding();
break;
}
//...
} while (moreItems == true);
Do While moreItems = True
' Cancellation causes OCE. We know how to handle it.
Try
success = bc.TryAdd(itemToAdd, 2, ct)
Catch ex As OperationCanceledException
bc.CompleteAdding()
Exit Do
End Try
Loop
Ein Beispiel für das Hinzufügen von Unterstützung für den Abbruch finden Sie im zweiten Beispiel unter Vorgehensweise: Hinzufügen und Entfernen von einzelnen Elementen zu bzw. aus einer BlockingCollection.
Angeben des Sammlungstyps
Wenn Sie ein BlockingCollection<T>Objekt erstellen, können Sie nicht nur die begrenzungsgebundene Kapazität, sondern auch den zu verwendenden Sammlungstyp angeben. Sie könnten z. B. ein ConcurrentQueue<T> für ein First In First Out (FIFO)-Verhalten spezifizieren oder ein ConcurrentStack<T> für ein Last In First Out (LIFO)-Verhalten. Sie können jede Sammlungsklasse verwenden, die die IProducerConsumerCollection<T> Schnittstelle implementiert. Der Standardsammlungstyp für BlockingCollection<T> ist ConcurrentQueue<T>. Das folgende Codebeispiel zeigt, wie Sie eine BlockingCollection<T> von Zeichenfolgen mit einer Kapazität von 1000 erstellen und einen ConcurrentBag<T> verwenden:
Dim bc = New BlockingCollection(Of String)(New ConcurrentBag(Of String()), 1000)
BlockingCollection<string> bc = new BlockingCollection<string>(new ConcurrentBag<string>(), 1000 );
Weitere Informationen finden Sie unter Anleitung: Hinzufügen von Begrenzungs- und Sperrfunktionalität zu einer Sammlung.
IEnumerable-Unterstützung
BlockingCollection<T> stellt eine GetConsumingEnumerable Methode bereit, mit der Benutzer foreach
(For Each
in Visual Basic) verwenden können, um Elemente zu entfernen, bis die Auflistung abgeschlossen ist. Das bedeutet, dass sie leer ist und keine weiteren Elemente hinzugefügt werden. Weitere Informationen finden Sie unter So verwenden Sie ForEach, um Elemente in einer BlockingCollection zu entfernen.
Verwendung vieler BlockingCollections als eine Einheit
Für Szenarien, in denen ein Verbraucher Elemente aus mehreren Auflistungen gleichzeitig übernehmen muss, können Sie Arrays von BlockingCollection<T> erstellen und die statischen Methoden TakeFromAny und AddToAny verwenden, um zu einer der Auflistungen im Array hinzuzufügen oder von ihr zu nehmen. Wenn eine Sammlung blockiert wird, versucht die Methode sofort eine andere, bis eine gefunden wird, die den Vorgang ausführen kann. Weitere Informationen finden Sie unter Anleitung: Verwenden von Arrays blockierender Sammlungen in einer Pipeline.