BlockingCollection 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:

  • Üretici-Tüketici deseninin bir uygulaması.

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

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

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

  • Ekleme ve kaldırma işlemi, engellemeyen veya belirli bir süreye kadar engelleyen "deneme" işlemleridir.

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

  • İptal belirteçleriyle 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ırlayıcı ve engellemeyi destekler. Sınırlayıcı, koleksiyonun maksimum kapasitesini ayarlayabileceğiniz anlamına gelir. Sınırlama, bellekteki koleksiyonun en büyük boyutunu denetlemenize olanak sağladığından ve üreten iş parçacıklarının tüketen iş parçacıklarının çok ilerisine geçmesini önlediğinden, belirli senaryolarda önemlidir.

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. Üreten bir iş parçacığı, başka öğe eklenmeyeceklerini belirtmek için çağırabilir CompleteAdding . Tüketiciler, koleksiyonun IsCompleted ne zaman boş olduğunu ve başka öğe eklenmeyeceklerini bilmek için ö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 true olduğu sürece koleksiyona öğe ekler ve ardından öğesini çağırır CompleteAdding. 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 kullanılabilirse, başvuruyla 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. Daha sonra iş parçacığı, koleksiyona yeniden erişmeye çalışmadan önce başka yararlı işler de yapabilir. 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. veya TryTake yöntemine TryAdd bir geçirip her yinelemede CancellationToken belirtecin IsCancellationRequested özelliğinin değerini denetleyerek bir döngü iptal edebilirsiniz. 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 örneği için Bkz . Nasıl yapılır: Bir BlockingCollection'dan Öğeleri Ayrı Ayrı Ekleme ve Alma.

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 ilk çıkış (FIFO) davranışı için veya ConcurrentStack<T> son ilk çıkış (LIFO) davranışı için bir belirtebilirsinizConcurrentQueue<T>. Arabirimini uygulayan herhangi bir koleksiyon sınıfını IProducerConsumerCollection<T> kullanabilirsiniz. için BlockingCollection<T> varsayılan koleksiyon türü şeklindedir ConcurrentQueue<T>. Aşağıdaki kod örneği, 1000 kapasiteye sahip ve ConcurrentBag<T>kullanan dizelerin nasıl oluşturulacağını BlockingCollection<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 (For EachVisual Basic'te) kullanmasına foreach olanak tanıyan bir GetConsumingEnumerable yöntem sağlar; bu da boş olduğu ve başka öğe eklenmeyecek olduğu anlamına gelir. Daha fazla bilgi için bkz . How to: Use ForEach to Remove Items in a BlockingCollection.

Birçok BlockingCollections'i Tek Olarak Kullanma

Tüketicinin aynı anda birden çok koleksiyondan öğe alması gereken senaryolar için dizileri BlockingCollection<T> oluşturabilir ve dizideki koleksiyonlardan herhangi birine eklenecek veya bu koleksiyonlardan alacak ve AddToAny gibi TakeFromAny 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 bkz . How to: Use Arrays of Blocking Collections in a Pipeline.

Ayrıca bkz.