BlockingCollection'a Genel Bakış

BlockingCollection<T> , aşağıdaki özellikleri sağlayan iş parçacığı açısından güvenli bir koleksiyon sınıfıdır:

  • Producer-Consumer deseninin bir uygulaması.

  • Birden çok iş parçacığından öğe ekleme ve alma eşzamanlı olarak yapılmaktadır.

  • İsteğe bağlı maksimum kapasite.

  • Koleksiyon boş veya dolu olduğunda engelleyen ekleme ve kaldırma işlemleri.

  • Engellemeyen veya belirli bir süreye kadar engelleyen ekleme ve kaldırma deneme işlemleridir.

  • Uygulayan tüm koleksiyon türlerini kapsüller IProducerConsumerCollection<T>

  • İptal belirteçlerini kullanarak iptal etme.

  • ile iki tür numaralandırma foreach (For Each Visual Basic'te):

    1. Salt okunur numaralandırma.

    2. Öğeleri numaralandırıldıkları gibi kaldıran numaralandırma.

Sınırlayıcı ve Engelleme Desteği

BlockingCollection<T> sınırlama ve engellemeyi destekler. Koleksiyonun maksimum kapasitesini belirleyebileceğiniz anlamına gelir. Sınırlama, belirli senaryolarda önemlidir çünkü bellekteki koleksiyonun maksimum boyutunu kontrol etmenizi sağlar ve üreten iş parçacıklarının, tüketen iş parçacıklarının çok önüne geçmesini engeller.

Birden çok iş parçacığı veya görev aynı anda koleksiyona öğe ekleyebilir ve koleksiyon belirtilen maksimum kapasiteye ulaşırsa, öğe kaldırılana kadar oluşturan iş parçacıkları engellenir. Birden çok tüketici öğeleri eşzamanlı olarak kaldırabilir ve koleksiyon boşsa, bir üretici öğe ekleyene kadar tüketen iş parçacıkları engellenir. Bir üretici iş parçacığı artık başka öğe eklenmeyeceğini belirtmek için CompleteAdding çağırabilir. Tüketiciler, koleksiyonun ne zaman boş olduğunu ve başka öğe eklenmeyeceğini bilmek için IsCompleted özelliğini izler. Aşağıdaki örnekte sınırlanmış kapasitesi 100 olan basit bir BlockingCollection gösterilmektedir. Bir üretici görevi, bazı dış koşullar geçerli olduğu sürece koleksiyona öğeler ekler ve ardından CompleteAdding çağırır. Tüketici görevi, özellik doğru olana kadar IsCompleted öğeleri alır.

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

Tam bir örnek için bkz . Nasıl yapılır: Bir BlockingCollection'dan Öğeleri Ayrı Ayrı Ekleme ve Alma.

Zamanlanmış Engelleme İşlemleri

Zamanlanmış engelleme TryAdd ve TryTake sınırlanmış koleksiyonlardaki işlemlerde yöntemi bir öğe eklemeye veya almaya çalışır. Bir öğe mevcutsa, referans olarak geçirilen değişkene yerleştirilir ve yöntem 'true' döndürür. Belirtilen zaman aşımı süresinden sonra hiçbir öğe alınmazsa yöntem false döndürür. İş parçacığı, koleksiyona yeniden erişmeye çalışmadan önce başka yararlı işler yapmakta serbesttir. Zamanlanmış engelleme erişimi örneği için , Nasıl yapılır: Bir BlockingCollection'dan Öğeleri Tek Tek Ekleme ve Alma makalesindeki ikinci örnağa bakın.

Ekleme ve Alma İşlemlerini İptal Etme

Ekleme ve Alma işlemleri genellikle döngü içinde gerçekleştirilir. Bir döngüyü iptal etmek için CancellationToken veya TryAdd yöntemine TryTake geçirip, her yinelemede belirtecin IsCancellationRequested özelliğinin değerini denetleyebilirsiniz. Değer true ise, tüm kaynakları temizleyip döngüden çıkararak iptal isteğine yanıt vermek size bağlı olur. Aşağıdaki örnekte, iptal belirtecini TryAdd alan bir aşırı yükleme ve bunu kullanan kod gösterilmektedir:

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

İptal desteği ekleme konusunda ikinci örneği görmek için Nasıl Yapılır: Bir BlockingCollection'dan Öğeleri Ayrı Ayrı Ekleme ve Alma'yı inceleyin.

Koleksiyon Türünü Belirtme

Oluşturduğunuzda BlockingCollection<T>, yalnızca sınırlanmış kapasiteyi değil, aynı zamanda kullanılacak koleksiyonun türünü de belirtebilirsiniz. Örneğin, ilk giren ilk çıkar (FIFO) davranışı için bir ConcurrentQueue<T> belirtebilir veya son giren ilk çıkar (LIFO) davranışı için bir ConcurrentStack<T> belirtebilirsiniz. Arayüzü uygulayan herhangi bir koleksiyon sınıfını kullanabilirsiniz. için BlockingCollection<T> varsayılan koleksiyon türü şeklindedir ConcurrentQueue<T>. Aşağıdaki kod örneği, 1000 kapasiteli ve BlockingCollection<T> kullanan bir dize koleksiyonunun nasıl oluşturulacağını ConcurrentBag<T> gösterir.

Dim bc = New BlockingCollection(Of String)(New ConcurrentBag(Of String()), 1000)
BlockingCollection<string> bc = new BlockingCollection<string>(new ConcurrentBag<string>(), 1000 );

Daha fazla bilgi için bkz . Nasıl yapılır: Bir Koleksiyona Sınırlayıcı ve Engelleme İşlevselliği Ekleme.

IEnumerable Desteği

BlockingCollection<T>, tüketicilerin koleksiyon tamamlanana kadar öğeleri kaldırmak için (GetConsumingEnumerableVisual Basic'te) kullanmasına foreach olanak tanıyan bir For Each yöntem sağlar; bu da boş olduğu ve başka öğe eklenmeyecek olduğu anlamına gelir. Daha fazla bilgi için Nasıl Yapılır: BlockingCollection'da Öğeleri Kaldırmak için ForEach Kullanma bölümüne bakın.

Birçok BlockingCollections'i Tek Olarak Kullanma

Bir tüketicinin aynı anda birden çok koleksiyondan öğe alması gereken senaryolar için BlockingCollection<T> içeren diziler oluşturabilir ve dizi içerisindeki koleksiyonlardan herhangi birine ekleme veya bu koleksiyonlardan çıkarma işlemleri yapmak üzere TakeFromAny ve AddToAny gibi statik yöntemleri kullanabilirsiniz. Bir koleksiyon engelleniyorsa, yöntemi işlemi gerçekleştirebilecek bir koleksiyon bulana kadar hemen başka bir koleksiyon dener. Daha fazla bilgi için şu makaleye bakın: Bir Boru Hattında Bloklayan Koleksiyon Dizileri Nasıl Kullanılır.

Ayrıca bakınız