Panoramica di BlockingCollectionBlockingCollection Overview

BlockingCollection<T> è una classe di raccolta thread-safe che offre le funzionalità seguenti:BlockingCollection<T> is a thread-safe collection class that provides the following features:

  • Implementazione del modello Producer-Consumer.An implementation of the Producer-Consumer pattern.

  • Aggiunta e rimozione simultanea di elementi da più thread.Concurrent adding and taking of items from multiple threads.

  • Capacità massima facoltativa.Optional maximum capacity.

  • Operazioni di inserimento e rimozione che si bloccano quando la raccolta è vuota o piena.Insertion and removal operations that block when collection is empty or full.

  • Operazioni "prova" di inserimento e rimozione che non si bloccano o che si bloccano per un periodo di tempo specificato.Insertion and removal "try" operations that do not block or that block up to a specified period of time.

  • Incapsulamento di qualsiasi tipo di raccolta che implementi IProducerConsumerCollection<T>Encapsulates any collection type that implements IProducerConsumerCollection<T>

  • Annullamento con token di annullamento.Cancellation with cancellation tokens.

  • Due tipi di enumerazione con foreach (For Each in Visual Basic):Two kinds of enumeration with foreach (For Each in Visual Basic):

    1. Enumerazione di sola lettura.Read-only enumeration.

    2. Enumerazione che rimuove gli elementi quando vengono enumerati.Enumeration that removes items as they are enumerated.

Supporto di delimitazione e bloccoBounding and Blocking Support

BlockingCollection<T> supporta delimitazione e blocco.BlockingCollection<T> supports bounding and blocking. La delimitazione consente di impostare la capacità massima della raccolta.Bounding means you can set the maximum capacity of the collection. La delimitazione è importante in determinati scenari poiché consente di controllare la dimensione massima della raccolta in memoria, impedendo ai thread Producer di spostarsi troppo oltre i thread Consumer.Bounding is important in certain scenarios because it enables you to control the maximum size of the collection in memory, and it prevents the producing threads from moving too far ahead of the consuming threads.

Più thread o attività possono aggiungere contemporaneamente elementi alla raccolta, e se la raccolta raggiunge la capacità massima specificata, i thread Producer si bloccano fino a quando non viene rimosso un elemento.Multiple threads or tasks can add items to the collection concurrently, and if the collection reaches its specified maximum capacity, the producing threads will block until an item is removed. Più Consumer possono rimuovere contemporaneamente elementi e quando la raccolta diventa vuota, i thread Consumer si bloccano fino a quando un Producer aggiunge un elemento.Multiple consumers can remove items concurrently, and if the collection becomes empty, the consuming threads will block until a producer adds an item. Un thread Producer può chiamare CompleteAdding per indicare che non verranno aggiunti altri elementi.A producing thread can call CompleteAdding to indicate that no more items will be added. I Consumer monitorano la proprietà IsCompleted per sapere quando la raccolta è vuota e non verranno aggiunti altri elementi.Consumers monitor the IsCompleted property to know when the collection is empty and no more items will be added. Nell'esempio seguente viene illustrato un semplice BlockingCollection con una capacità delimitata di 100.The following example shows a simple BlockingCollection with a bounded capacity of 100. Un'attività Producer aggiunge elementi alla raccolta, purché una condizione esterna sia true e quindi chiama CompleteAdding.A producer task adds items to the collection as long as some external condition is true, and then calls CompleteAdding. L'attività di tipo Consumer accetta elementi finché la proprietà IsCompleted è true.The consumer task takes items until the IsCompleted property is true.

// 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 number.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 numbers.Count = dataItems.BoundedCapacity
                              dataItems.Add(item)
                          End While

                          ' Let consumer know we are done.
                          dataItems.CompleteAdding()
                      End Sub)

Per un esempio completo, vedere Procedura: Aggiungere e rimuovere singoli elementi di un oggetto BlockingCollection.For a complete example, see How to: Add and Take Items Individually from a BlockingCollection.

Operazioni di blocco temporizzateTimed Blocking Operations

Nelle operazioni di blocco temporizzate TryAdd e TryTake sulle raccolte delimitate il metodo tenta di aggiungere o rimuovere un elemento.In timed blocking TryAdd and TryTake operations on bounded collections, the method tries to add or take an item. Se è disponibile un elemento, questo viene posizionato nella variabile che è stata passata per riferimento e il metodo restituisce true.If an item is available it is placed into the variable that was passed in by reference, and the method returns true. Se dopo un periodo di timeout specificato non viene recuperato alcun elemento, il metodo restituisce false.If no item is retrieved after a specified time-out period the method returns false. Il thread è quindi libero di eseguire altre operazioni utili prima di tentare nuovamente di accedere alla raccolta.The thread is then free to do some other useful work before trying again to access the collection. Per un esempio di accesso con blocco temporizzato, vedere il secondo esempio in Procedura: Aggiungere e rimuovere singoli elementi di un oggetto BlockingCollection.For an example of timed blocking access, see the second example in How to: Add and Take Items Individually from a BlockingCollection.

Annullamento di operazioni di aggiunta e rimozioneCancelling Add and Take Operations

Le operazioni di aggiunta e rimozione solitamente vengono eseguite in un ciclo.Add and Take operations are typically performed in a loop. È possibile annullare un ciclo passando un CancellationToken al metodo TryAdd o TryTake e quindi controllando il valore della proprietà IsCancellationRequested del token in ogni iterazione.You can cancel a loop by passing in a CancellationToken to the TryAdd or TryTake method, and then checking the value of the token's IsCancellationRequested property on each iteration. Se il valore è true, l'utente deve decidere se rispondere alla richiesta di annullamento cancellando tutte le risorse e uscendo dal ciclo.If the value is true, then it is up to you to respond the cancellation request by cleaning up any resources and exiting the loop. Nell'esempio seguente viene illustrato un overload di TryAdd che accetta un token di annullamento e il codice che viene usato:The following example shows an overload of TryAdd that takes a cancellation token, and the code that uses it:

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

Per un esempio di aggiunta del supporto per l'annullamento, vedere il secondo esempio in Procedura: Aggiungere e rimuovere singoli elementi di un oggetto BlockingCollection.For an example of how to add cancellation support, see the second example in How to: Add and Take Items Individually from a BlockingCollection.

Specifica del tipo di raccoltaSpecifying the Collection Type

Quando si crea un oggetto BlockingCollection<T>, è possibile specificare non solo la capacità delimitata ma anche il tipo di raccolta da usare.When you create a BlockingCollection<T>, you can specify not only the bounded capacity but also the type of collection to use. Ad esempio, è possibile specificare ConcurrentQueue<T> per il comportamento FIFO (First In, First Out) o ConcurrentStack<T> per il comportamento LIFO (Last In, First Out).For example, you could specify a ConcurrentQueue<T> for first in-first out (FIFO) behavior, or a ConcurrentStack<T> for last in-first out (LIFO) behavior. È possibile usare qualsiasi classe di raccolta che implementa l'interfaccia IProducerConsumerCollection<T>.You can use any collection class that implements the IProducerConsumerCollection<T> interface. Il tipo di raccolta predefinito per BlockingCollection<T> è ConcurrentQueue<T>.The default collection type for BlockingCollection<T> is ConcurrentQueue<T>. L'esempio di codice seguente illustra come creare un oggetto BlockingCollection<T> di stringhe con capacità 1000, che usa un oggetto ConcurrentBag<T>:The following code example shows how to create a BlockingCollection<T> of strings that has a capacity of 1000 and uses a ConcurrentBag<T>:

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

Per altre informazioni, vedere Procedura: Aggiungere funzionalità di delimitazione e blocco a una raccolta.For more information, see How to: Add Bounding and Blocking Functionality to a Collection.

Supporto di IEnumerableIEnumerable Support

BlockingCollection<T> offre un metodo GetConsumingEnumerable che consente agli utenti di usare foreach (For Each in Visual Basic) per rimuovere gli elementi fino a quando non viene completata la raccolta, ovvero finché non è vuota e non vengono aggiunti altri elementi.BlockingCollection<T> provides a GetConsumingEnumerable method that enables consumers to use foreach (For Each in Visual Basic) to remove items until the collection is completed, which means it is empty and no more items will be added. Per altre informazioni, vedere Procedura: usare ForEach per rimuovere elementi in un oggetto BlockingCollection.For more information, see How to: Use ForEach to Remove Items in a BlockingCollection.

Uso di più oggetti BlockingCollections come uno soloUsing Many BlockingCollections As One

Per gli scenari in cui un Consumer deve rimuovere elementi da più raccolte contemporaneamente, è possibile creare matrici di BlockingCollection<T> e usare i metodi statici, ad esempio TakeFromAny e AddToAny che eseguiranno operazioni di aggiunta o rimozione in qualsiasi raccolta nella matrice.For scenarios in which a consumer needs to take items from multiple collections simultaneously, you can create arrays of BlockingCollection<T> and use the static methods such as TakeFromAny and AddToAny that will add to or take from any of the collections in the array. Se una raccolta è bloccata, il metodo ne cerca immediatamente un'altra finché non ne trova una che può eseguire l'operazione.If one collection is blocking, the method immediately tries another until it finds one that can perform the operation. Per altre informazioni, vedere Procedura: usare matrici di BlockingCollection in una pipeline.For more information, see How to: Use Arrays of Blocking Collections in a Pipeline.

Vedere ancheSee Also

System.Collections.Concurrent
Raccolte e strutture di datiCollections and Data Structures
Raccolte thread-safeThread-Safe Collections