Información general sobre BlockingCollectionBlockingCollection Overview

BlockingCollection<T> es una clase de colección segura para subprocesos que proporciona las siguientes características:BlockingCollection<T> is a thread-safe collection class that provides the following features:

  • Una implementación del patrón productor-consumidor.An implementation of the Producer-Consumer pattern.

  • Agregar y quitar elementos en varios subprocesos de forma simultánea.Concurrent adding and taking of items from multiple threads.

  • Capacidad máxima opcional.Optional maximum capacity.

  • Operaciones de inserción y eliminación que se bloquean cuando la colección está vacía o completa.Insertion and removal operations that block when collection is empty or full.

  • Inserción y eliminación de operaciones "try" que no se bloquean o que se bloquean en un período de tiempo especificado.Insertion and removal "try" operations that do not block or that block up to a specified period of time.

  • Encapsula cualquier tipo de colección que implementa IProducerConsumerCollection<T>.Encapsulates any collection type that implements IProducerConsumerCollection<T>

  • Cancelación con tokens de cancelación.Cancellation with cancellation tokens.

  • Dos tipos de enumeraciones con foreach (For Each en Visual Basic):Two kinds of enumeration with foreach (For Each in Visual Basic):

    1. Enumeración de solo lectura.Read-only enumeration.

    2. Enumeración que quita los elementos que se enumeran.Enumeration that removes items as they are enumerated.

Compatibilidad con límites y bloqueosBounding and Blocking Support

BlockingCollection<T> admite límites y bloqueos.BlockingCollection<T> supports bounding and blocking. Los límites implican que puede establecer la capacidad máxima de la colección.Bounding means you can set the maximum capacity of the collection. Los límites son importantes en ciertos escenarios, porque le permiten controlar el tamaño máximo de la colección en memoria y evitan que los subprocesos de producción vayan demasiado por delante de los subprocesos de consumo.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.

Varios subprocesos o tareas pueden agregar elementos a la colección de forma simultánea y, si la colección alcanza su capacidad máxima especificada, los subprocesos de producción se bloquearán hasta que se quite 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. Varios consumidores pueden quitar elementos de forma simultánea y, si la colección está vacía, los subprocesos de consumo se bloquearán hasta que un productor agregue 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 subproceso de producción puede llamar a CompleteAdding para indicar que no se agregarán más elementos.A producing thread can call CompleteAdding to indicate that no more items will be added. Los consumidores supervisan la propiedad IsCompleted para saber cuándo está vacía la colección y no se agregarán más elementos.Consumers monitor the IsCompleted property to know when the collection is empty and no more items will be added. En el ejemplo siguiente, se muestra una clase BlockingCollection sencilla con una capacidad limitada de 100.The following example shows a simple BlockingCollection with a bounded capacity of 100. Una tarea de producción agrega elementos a la colección siempre que alguna condición externa sea true y después llama a CompleteAdding.A producer task adds items to the collection as long as some external condition is true, and then calls CompleteAdding. La tarea de consumidor toma elementos hasta que la propiedad IsCompleted es 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 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)

Para obtener un ejemplo completo, vea Cómo: Agregar y tomar elementos de forma individual en una clase BlockingCollection.For a complete example, see How to: Add and Take Items Individually from a BlockingCollection.

Operaciones de bloqueo cronometradasTimed Blocking Operations

En las operaciones de bloqueo cronometradas TryAdd y TryTake en colecciones limitadas, el método intenta agregar o quitar un elemento.In timed blocking TryAdd and TryTake operations on bounded collections, the method tries to add or take an item. Si un elemento está disponible, se coloca en la variable que ha pasado la referencia y el método devuelve true.If an item is available it is placed into the variable that was passed in by reference, and the method returns true. Si no se recupera ningún elemento después de un período de tiempo de espera especificado, el método devuelve false.If no item is retrieved after a specified time-out period the method returns false. El subproceso es libre para realizar otro trabajo útil antes de intentar acceder de nuevo a la colección.The thread is then free to do some other useful work before trying again to access the collection. Para obtener un ejemplo de acceso de bloqueo cronometrado, vea el segundo ejemplo de Cómo: Agregar y tomar elementos de forma individual en una clase BlockingCollection.For an example of timed blocking access, see the second example in How to: Add and Take Items Individually from a BlockingCollection.

Cancelar operaciones de agregar y tomarCancelling Add and Take Operations

Las operaciones de agregar y tomar se realizan normalmente en un bucle.Add and Take operations are typically performed in a loop. Puede cancelar un bucle al pasar CancellationToken a los métodos TryAdd o TryTake, y después comprobar el valor de la propiedad IsCancellationRequested del token en cada iteración.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. Si el valor es true, puede decidir si responde a la solicitud de cancelación limpiando algún recurso y saliendo del bucle.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. En el ejemplo siguiente, se muestra una sobrecarga de TryAdd que toma un token de cancelación y el código que lo usa: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

Para obtener un ejemplo de cómo agregar compatibilidad con la cancelación, vea el segundo ejemplo de Cómo: Agregar y tomar elementos de forma individual en una clase 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.

Especificar el tipo de colecciónSpecifying the Collection Type

Cuando se crea una BlockingCollection<T>, puede especificar no solo la capacidad limitada, sino también el tipo de colección que se usará.When you create a BlockingCollection<T>, you can specify not only the bounded capacity but also the type of collection to use. Por ejemplo, puede especificar un objeto ConcurrentQueue<T> para un comportamiento FIFO (primero en entrar, primero en salir) o un objeto ConcurrentStack<T> para un comportamiento LIFO (último en entrar, primero en salir).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. Puede usar cualquier clase de colección que implemente la interfaz IProducerConsumerCollection<T>.You can use any collection class that implements the IProducerConsumerCollection<T> interface. El tipo de colección predeterminado para BlockingCollection<T> es ConcurrentQueue<T>.The default collection type for BlockingCollection<T> is ConcurrentQueue<T>. En el ejemplo de código siguiente, se muestra cómo crear una BlockingCollection<T> de cadenas que tiene una capacidad de 1000 y usa un objeto 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 );  

Para obtener más información, vea Cómo: Agregar la funcionalidad de límite y bloqueo a una colección.For more information, see How to: Add Bounding and Blocking Functionality to a Collection.

Compatibilidad con IEnumerableIEnumerable Support

BlockingCollection<T> proporciona un método GetConsumingEnumerable que permite a los consumidores usar foreach (For Each en Visual Basic) para quitar elementos hasta que la colección está completa, lo que significa que está vacía y no se agregan más elementos.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. Para obtener más información, vea Cómo: Usar ForEach para quitar elementos de BlockingCollection.For more information, see How to: Use ForEach to Remove Items in a BlockingCollection.

Usar muchas BlockingCollections como unaUsing Many BlockingCollections As One

Para escenarios en los que un consumidor necesita tomar elementos de varias colecciones de forma simultánea, se pueden crear matrices de BlockingCollection<T> y usar los métodos estáticos, como TakeFromAny y AddToAny, que agregarán a cualquiera de las colecciones de la matriz o tomarán desde ellas.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. Si se bloquea una colección, el método intenta otra de forma inmediata hasta que encuentra una que pueda realizar la operación.If one collection is blocking, the method immediately tries another until it finds one that can perform the operation. Para obtener más información, vea Cómo: Usar matrices de colecciones de bloqueo en una canalización.For more information, see How to: Use Arrays of Blocking Collections in a Pipeline.

Vea tambiénSee also