Cara bekerja dengan ConcurrentBag dan ConcurrentDictionary di .Net

Koleksi bersamaan di .Net terkandung di dalam ruang nama System.Collections.Concurrent dan menyediakan implementasi kelas koleksi tanpa kunci dan thread-aman. Koleksi aman thread pertama kali diperkenalkan di .Net 4, dan koleksi pertama kali diperkenalkan sebagai bagian dari .Net Framework 1.0 dan tersedia di namespace System.Collections.

Anda dapat memanfaatkan koleksi serentak untuk bekerja dengan koleksi tanpa harus menulis kode tambahan apa pun untuk sinkronisasi utas. Anda dapat melihat artikel saya di ConcurrentStack dan ConcurrentQueue.

ConcurrentBag

ConcurrentBag menyediakan koleksi thread-safe dari serangkaian elemen yang tidak berurutan. Berikut daftar metode penting kelas ConcurrentBag.

  • Tambahkan (elemen T) - Metode ini digunakan untuk menambahkan elemen ke ConcurrentBag.
  • TryPeek (out T) - Metode ini digunakan untuk mengambil elemen dari ConcurrentBag tanpa menghapusnya.
  • TryTake (out T) - Metode ini digunakan untuk mengambil elemen dari ConcurrentBag. Perhatikan bahwa metode ini menghapus item dari koleksi.

Cuplikan kode berikut menggambarkan bagaimana Anda dapat membuat koleksi ConcurrentBag dan menyimpan item ke dalamnya.

ConcurrentBag concurrentBag = new ConcurrentBag();

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

    {

        concurrentBag.Add(i);

    }

Jika Anda akan mengambil item dalam koleksi, Anda harus menulis kode berikut:

while (concurrentBag.Count > 0)

  {

      Int32 element;

      if (concurrentBag.TryTake(out element))

       {

         Console.WriteLine(element);

       }

  }

Perhatikan bagaimana metode TryTake telah digunakan: Metode ini mengembalikan nilai benar saat berhasil, salah jika tidak. Metode TryTake juga menghapus item dari koleksi. Perulangan while melanjutkan eksekusi hingga jumlah item dalam koleksi lebih besar dari nol. Berikut daftar kode lengkap untuk referensi Anda.

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

Kamus adalah kumpulan umum pasangan kunci / nilai. Ini lebih cepat daripada Hashtable karena menghilangkan overhead tinju dan un-boxing. ConcurrentDictionary berada di dalam namespace System.Collections.Concurrent dan mewakili kamus thread-safe.

Anggota penting dari kelas ConcurrentDictionary mencakup yang berikut:

  • TryAdd: Metode ini digunakan untuk menambahkan item dalam instance ConcurrentDictionary. Perhatikan bahwa metode ini memunculkan pengecualian jika kunci sudah ada dalam koleksi.
  • TryGetValue: Metode ini digunakan untuk mengambil item dari koleksi.
  • TryRemove: Metode ini digunakan untuk menghapus item dari koleksi.
  • TryUpdate: Metode ini digunakan untuk memperbarui kunci tertentu dalam instance ConcurrentDictionary dengan nilai baru yang diberikan.

Cuplikan kode berikut menunjukkan bagaimana Anda dapat membuat instance ConcurrentDictionary dan menambahkan item ke dalamnya:

ConcurrentDictionary obj = new ConcurrentDictionary();

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

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

Jika Anda sekarang mencoba menambahkan item lain tetapi dengan kunci yang sama, gagal. Lihat cuplikan kode di bawah ini.

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

Nilai variabel sukses adalah "false" karena upaya untuk menambahkan nilai dengan kunci yang sama gagal.

Cuplikan kode berikut mengilustrasikan bagaimana Anda dapat mengambil item dari koleksi berdasarkan kunci.

string item = null;

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

Jika Anda akan mengambil semua item dalam koleksi, Anda dapat menggunakan cuplikan kode berikut sebagai gantinya.

foreach(var v in obj)

    {

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

    }

Cuplikan kode berikut menunjukkan bagaimana Anda dapat menghapus item dari koleksi.

string item = null;

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

Jika Anda akan menghapus semua item, cuplikan kode berikut dapat digunakan sebagai gantinya.

obj.Clear();

Sekarang, pertimbangkan dua metode statis berikut.

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);

            }

        }

Berikut cara menjalankan dua metode di atas pada dua contoh Tugas secara bersamaan - satu untuk menyimpan nilai ke dalam koleksi dan yang lainnya untuk membaca nilai dari koleksi.

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

}

Jika Anda menjalankan kode di atas, pengecualian tidak akan dilempar karena koleksi di sini aman untuk thread.