Bagaimana bekerja dengan BlockingCollection di C #

Pertimbangkan skenario di mana beberapa utas akan membaca dan menulis ke antrian. Lebih khusus lagi, Anda mungkin memiliki pada titik waktu yang sama, beberapa produsen menyimpan data dan beberapa konsumen mengambilnya dari penyimpanan data umum. Karenanya, Anda memerlukan mekanisme sinkronisasi yang tepat untuk menyinkronkan akses ke data ini.

Di sinilah tepatnya kelas BlockingCollection datang untuk menyelamatkan. Meskipun ada banyak cara lain, kelas ini menyediakan salah satu cara paling efisien untuk menyinkronkan akses ke data Anda. Kelas BlockingCollection termasuk dalam namespace System.Collections.Concurrent.

Apa itu BlockingCollection?

BlockingCollection adalah kumpulan thread-aman di mana Anda dapat menambahkan dan menghapus data beberapa thread secara bersamaan. Ini direpresentasikan dalam .Net melalui kelas BlockingCollection; Anda dapat menggunakan kelas ini untuk mengimplementasikan pola produsen-konsumen.

Dalam pola produsen-konsumen, Anda memiliki dua komponen berbeda yang berjalan di dua utas berbeda. Ini termasuk komponen produsen yang menghasilkan beberapa data yang didorong ke antrian, dan konsumen yang menggunakan data yang disimpan dalam antrian. Saat Anda menggunakan BlockingCollection, Anda dapat menentukan kapasitas terbatas serta jenis koleksi yang ingin Anda gunakan.

Jenis BlockingCollection bertindak sebagai pembungkus di atas instance jenis IProducerConsumerCollection. Dengan kata lain, ia bertindak sebagai pembungkus atas koleksi lain yang pada gilirannya mengimplementasikan antarmuka IProducerConsumerCollection. Sebagai contoh, kelas ConcurrentBag, ConcurrentQueue, dan ConcurrentStack dapat digunakan dengan BlockingCollection karena semuanya mengimplementasikan antarmuka IProducerConsumerCollection.

Perhatikan bahwa antarmuka IProducerConsumerCollection berisi deklarasi metode yang dapat digunakan untuk bekerja dengan koleksi yang aman untuk thread. MSDN menyatakan: "Mendefinisikan metode untuk memanipulasi koleksi thread-safe yang dimaksudkan untuk penggunaan produsen / konsumen. Antarmuka ini menyediakan representasi terpadu untuk koleksi produsen / konsumen sehingga abstraksi tingkat yang lebih tinggi seperti System.Collections.Concurrent.BlockingCollection dapat menggunakan koleksi sebagai mekanisme penyimpanan yang mendasarinya. "

Cuplikan kode berikut menunjukkan bagaimana Anda dapat membuat instance string BlockingCollection.

var blockingCollection = new BlockingCollection();

Saat menggunakan BlockingCollection, Anda bisa menambahkan data ke koleksi baik menggunakan metode Tambah atau metode TryAdd. Sekarang mari kita pahami perbedaan antara kedua metode ini.

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.

Perhatikan bagaimana kami menetapkan boundedCapacity saat membuat instance BlockingCollection seperti yang ditunjukkan dalam cuplikan kode yang diberikan di atas. Ini ditentukan untuk menunjukkan ukuran terbatas dari contoh koleksi.

Anda juga dapat menggunakan metode TryAdd untuk menambahkan item ke instance BlockingCollection. Dalam metode ini, Anda dapat menggunakan nilai batas waktu. Jika operasi penambahan gagal dalam waktu yang ditentukan, metode TryAdd mengembalikan false. Cuplikan kode berikut menunjukkan bagaimana Anda dapat memanfaatkan metode TryAdd untuk menambahkan item ke instance BlockingCollection.

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

}

Untuk menghapus item dari BlockingCollection, Anda dapat menggunakan metode Take atau TryTake. Perhatikan bahwa metode Ambil memblokir jika tidak ada item dalam koleksi dan membuka blokir segera setelah item baru ditambahkan ke koleksi. Metode TryTake juga dapat digunakan untuk menghapus item dari instance BlockingCollection. Anda dapat menentukan nilai waktu tunggu dengan metode ini sehingga metode tersebut memblokir (hingga waktu yang ditentukan berlalu) hingga item ditambahkan ke koleksi. Jika sebuah item tidak dapat dihapus dari koleksi selama waktu ini (waktu tunggu yang ditentukan), metode TryTake akan mengembalikan false.

Potongan kode berikut mengilustrasikan bagaimana metode TryTake dapat digunakan untuk menghapus item dari instance tipe BlockingCollection.

int item;

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

{

   Console.WriteLine(item);

}

Berikut daftar kode lengkap untuk referensi Anda. Program ini mengilustrasikan bagaimana Anda dapat menggunakan BlockingCollection untuk menambah dan menghapus item ke dan dari koleksi.

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

       }

   }