So arbeiten Sie mit ConcurrentBag und ConcurrentDictionary in .Net

Gleichzeitige Sammlungen in .Net sind im Namespace System.Collections.Concurrent enthalten und bieten sperrfreie und threadsichere Implementierungen der Sammlungsklassen. Thread-sichere Sammlungen wurden erstmals in .Net 4 eingeführt, und Sammlungen wurden erstmals als Teil von .Net Framework 1.0 eingeführt und waren im System.Collections-Namespace verfügbar.

Sie können die gleichzeitigen Sammlungen nutzen, um mit Sammlungen zu arbeiten, ohne dass zusätzlicher Code für die Thread-Synchronisierung geschrieben werden muss. Sie können meinen Artikel über ConcurrentStack und ConcurrentQueue lesen.

ConcurrentBag

Die ConcurrentBag bietet eine thread-sichere Sammlung eines ungeordneten Satzes von Elementen. Hier ist die Liste der wichtigen Methoden der ConcurrentBag-Klasse.

  • Hinzufügen (T-Element) - Mit dieser Methode wird dem ConcurrentBag ein Element hinzugefügt.
  • TryPeek (out T) - Mit dieser Methode wird ein Element aus ConcurrentBag abgerufen, ohne es zu entfernen.
  • TryTake (out T) - Mit dieser Methode wird ein Element aus ConcurrentBag abgerufen. Beachten Sie, dass diese Methode das Element aus der Sammlung entfernt.

Das folgende Codeausschnitt zeigt, wie Sie eine ConcurrentBag-Sammlung erstellen und Elemente darin speichern können.

ConcurrentBag concurrentBag = new ConcurrentBag();

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

    {

        concurrentBag.Add(i);

    }

Wenn Sie die Elemente in der Sammlung abrufen möchten, sollten Sie den folgenden Code schreiben:

while (concurrentBag.Count > 0)

  {

      Int32 element;

      if (concurrentBag.TryTake(out element))

       {

         Console.WriteLine(element);

       }

  }

Beachten Sie, wie die TryTake-Methode verwendet wurde: Sie gibt bei Erfolg true zurück, andernfalls false. Die TryTake-Methode entfernt das Element auch aus der Sammlung. Die while-Schleife setzt die Ausführung fort, bis die Anzahl der Elemente in der Sammlung größer als Null ist. Hier ist die vollständige Codeliste als Referenz.

static void Main(string[] args)

        {

            ConcurrentBag concurrentBag = new ConcurrentBag();

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

            {

                concurrentBag.Add(i);

            }

            while (concurrentBag.Count > 0)

            {

                Int32 element;

                if (concurrentBag.TryTake(out element))

                {

                    Console.WriteLine(element);

                }

            }

            Console.Read();

        }

ConcurrentDictionary

Ein Wörterbuch ist eine generische Sammlung von Schlüssel / Wert-Paaren. Es ist schneller als ein Hashtable, da es den Aufwand für das Ein- und Auspacken beseitigt. Das ConcurrentDictionary ist im System.Collections.Concurrent-Namespace enthalten und repräsentiert ein thread-sicheres Wörterbuch.

Zu den wichtigen Mitgliedern der ConcurrentDictionary-Klasse gehören:

  • TryAdd: Mit dieser Methode wird ein Element zur ConcurrentDictionary-Instanz hinzugefügt. Beachten Sie, dass diese Methode eine Ausnahme auslöst, wenn der Schlüssel bereits in der Auflistung vorhanden ist.
  • TryGetValue: Mit dieser Methode wird ein Element aus der Sammlung abgerufen.
  • TryRemove: Mit dieser Methode wird ein Element aus der Sammlung entfernt.
  • TryUpdate: Mit dieser Methode wird ein bestimmter Schlüssel in der ConcurrentDictionary-Instanz mit dem neuen angegebenen Wert aktualisiert.

Das folgende Codefragment zeigt, wie Sie eine ConcurrentDictionary-Instanz erstellen und Elemente hinzufügen können:

ConcurrentDictionary obj = new ConcurrentDictionary();

obj.TryAdd("X001", "This is the first value.");

obj.TryAdd("X002", "This is the second value.");

Wenn Sie jetzt versuchen, ein anderes Element mit demselben Schlüssel hinzuzufügen, schlägt dies fehl. Siehe den folgenden Codeausschnitt.

bool success = obj.TryAdd("X002", "This is the third value.");

Der Wert der Erfolgsvariablen ist "false", da der Versuch, einen Wert mit demselben Schlüssel hinzuzufügen, fehlschlägt.

Das folgende Codeausschnitt zeigt, wie Sie ein Element basierend auf einem Schlüssel aus der Sammlung abrufen können.

string item = null;

bool isExist = obj.TryGetValue("X001", out item);

Wenn Sie alle Elemente in der Sammlung abrufen möchten, können Sie stattdessen das folgende Codeausschnitt verwenden.

foreach(var v in obj)

    {

        Console.WriteLine(v.Key + "---" + v.Value);

    }

Das folgende Codeausschnitt zeigt, wie Sie ein Element aus der Sammlung entfernen können.

string item = null;

bool result = obj.TryRemove("X001", out item);

Wenn Sie alle Elemente entfernen, kann stattdessen das folgende Codefragment verwendet werden.

obj.Clear();

Betrachten Sie nun die folgenden zwei statischen Methoden.

static void FirstTask(ConcurrentDictionary obj)

        {

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

            {

                obj.TryAdd(i.ToString(), i.ToString());

                Thread.Sleep(100);

            }

        }

        static void SecondTask(ConcurrentDictionary obj)

        {

            Thread.Sleep(1000);

            foreach (var item in obj)

            {

                Console.WriteLine("Key: "+item.Key + "   Value: " + item.Value);

                Thread.Sleep(100);

            }

        }

So können Sie die beiden oben genannten Methoden auf zwei Task-Instanzen gleichzeitig ausführen - eine zum Speichern von Werten in der Auflistung und die andere zum Lesen von Werten aus der Auflistung.

ConcurrentDictionary obj = new ConcurrentDictionary();

Task firstTask = Task.Run(() => FirstTask(obj));           

Task secondTask = Task.Run(() => SecondTask(obj));           

try

{

  Task.WaitAll(firstTask, secondTask);

}

catch (AggregateException ex)

{

   //Write your own code here to handle exception

}

Wenn Sie den obigen Code ausführen, wird keine Ausnahme ausgelöst, da die Sammlung hier threadsicher ist.