So arbeiten Sie mit BlockingCollection in C #

Stellen Sie sich ein Szenario vor, in dem mehrere Threads in eine Warteschlange lesen und schreiben würden. Insbesondere haben Sie möglicherweise zum gleichen Zeitpunkt mehrere Hersteller, die Daten speichern, und mehrere Verbraucher, die sie aus einem gemeinsamen Datenspeicher abrufen. Daher benötigen Sie einen geeigneten Synchronisationsmechanismus, um den Zugriff auf diese Daten zu synchronisieren.

Genau hier kommt die BlockingCollection-Klasse zur Rettung. Obwohl es viele andere Möglichkeiten gibt, bietet diese Klasse eine der effizientesten Möglichkeiten, den Zugriff auf Ihre Daten zu synchronisieren. Die BlockingCollection-Klasse gehört zum Namespace System.Collections.Concurrent.

Was ist eine BlockingCollection?

Die BlockingCollection ist eine thread-sichere Sammlung, in der mehrere Threads gleichzeitig Daten hinzufügen und entfernen können. Es wird in .Net durch die BlockingCollection-Klasse dargestellt. Mit dieser Klasse können Sie ein Producer-Consumer-Muster implementieren.

Im Producer-Consumer-Muster haben Sie zwei unterschiedliche Komponenten, die auf zwei verschiedenen Threads ausgeführt werden. Dazu gehören eine Herstellerkomponente, die einige Daten erzeugt, die in die Warteschlange verschoben werden, und ein Verbraucher, der die in der Warteschlange gespeicherten Daten verwendet. Wenn Sie eine BlockingCollection verwenden, können Sie die begrenzte Kapazität sowie den Typ der Sammlung angeben, die Sie verwenden möchten.

Der Typ BlockingCollection fungiert als Wrapper für eine Instanz vom Typ IProducerConsumerCollection. Mit anderen Worten, es fungiert als Wrapper für eine andere Sammlung, die wiederum die IProducerConsumerCollection-Schnittstelle implementiert. Beispielsweise können die Klassen ConcurrentBag, ConcurrentQueue und ConcurrentStack mit einer BlockingCollection verwendet werden, da alle die IProducerConsumerCollection-Schnittstelle implementieren.

Beachten Sie, dass die IProducerConsumerCollection-Schnittstelle eine Deklaration von Methoden enthält, die für die Arbeit mit threadsicheren Sammlungen verwendet werden können. In der MSDN heißt es: "Definiert Methoden zum Bearbeiten von thread-sicheren Sammlungen, die für die Verwendung durch Hersteller / Verbraucher bestimmt sind. Diese Schnittstelle bietet eine einheitliche Darstellung für Erzeuger / Verbraucher-Sammlungen, sodass übergeordnete Abstraktionen wie System.Collections.Concurrent.BlockingCollection die Sammlung als verwenden können der zugrunde liegende Speichermechanismus. "

Das folgende Codefragment zeigt, wie Sie eine Instanz einer BlockingCollection von Zeichenfolgen erstellen können.

var blockingCollection = new BlockingCollection();

Wenn Sie eine BlockingCollection verwenden, können Sie der Sammlung Daten hinzufügen, entweder mit der Add-Methode oder der TryAdd-Methode. Lassen Sie uns nun den Unterschied zwischen diesen beiden Methoden verstehen.

BlockingCollection data = new BlockingCollection(boundedCapacity: 3);

data.Add(1);

data.Add(2);

data.Add(3);

data.Add(4); //This would block until an item is removed from the collection.

Beachten Sie, wie wir boundedCapacity beim Erstellen einer Instanz einer BlockingCollection angegeben haben, wie im oben angegebenen Code-Snippet gezeigt. Dies wird angegeben, um die begrenzte Größe der Sammlungsinstanz anzugeben.

Sie können auch die TryAdd-Methode verwenden, um einer BlockingCollection-Instanz ein Element hinzuzufügen. Bei dieser Methode können Sie einen Timeout-Wert verwenden. Wenn der Addiervorgang innerhalb der angegebenen Zeit fehlschlägt, gibt die TryAdd-Methode false zurück. Das folgende Codefragment zeigt, wie Sie die TryAdd-Methode nutzen können, um einer Instanz von BlockingCollection ein Element hinzuzufügen.

BlockingCollection data = new BlockingCollection(boundedCapacity: 3);

data.Add(1);

data.Add(2);

data.Add(3);

if (data.TryAdd(4, TimeSpan.FromMilliseconds(100)))

{

   Console.WriteLine("A new item was successfully added to the collection.");

}

else

{

   Console.WriteLine("Failed to add a new item to the collection.");

}

Um ein Element aus einer BlockingCollection zu entfernen, können Sie die Take- oder die TryTake-Methode verwenden. Beachten Sie, dass die Take-Methode blockiert, wenn sich keine Elemente in der Sammlung befinden, und die Blockierung aufhebt, sobald ein neues Element zur Sammlung hinzugefügt wird. Die TryTake-Methode kann auch verwendet werden, um ein Element aus einer Instanz einer BlockingCollection zu entfernen. Mit dieser Methode können Sie einen Zeitüberschreitungswert angeben, sodass die Methode blockiert (bis die angegebene Zeit abgelaufen ist), bis ein Element zur Sammlung hinzugefügt wird. Wenn ein Element während dieser Zeit (das angegebene Zeitlimit) nicht aus der Sammlung entfernt werden konnte, gibt die TryTake-Methode false zurück.

Das folgende Codeausschnitt zeigt, wie mit der TryTake-Methode ein Element aus einer Instanz vom Typ BlockingCollection entfernt werden kann.

int item;

while (data.TryTake(out item, TimeSpan.FromMilliseconds(100)))

{

   Console.WriteLine(item);

}

Hier ist eine vollständige Codeliste als Referenz. Dieses Programm zeigt, wie Sie mit einer BlockingCollection Elemente zu einer Sammlung hinzufügen und daraus entfernen können.

 class Program

   {

       private static BlockingCollection data = new BlockingCollection();

       private static void Producer()

       {

           for (int ctr = 0; ctr < 10; ctr++)

           {

               data.Add(ctr);

               Thread.Sleep(100);

           }

       }

       private static void Consumer()

       {

           foreach (var item in data.GetConsumingEnumerable())

           {

               Console.WriteLine(item);

           }

       }

       static void Main(string[] args)

       {

           var producer = Task.Factory.StartNew(() => Producer());

           var consumer = Task.Factory.StartNew(() => Consumer());

           Console.Read();

       }

   }