Vue d'ensemble de BlockingCollectionBlockingCollection Overview

BlockingCollection<T> est une classe de collection thread-safe qui fournit les fonctionnalités suivantes :BlockingCollection<T> is a thread-safe collection class that provides the following features:

  • Implémentation du modèle producteur-consommateur.An implementation of the Producer-Consumer pattern.

  • Ajout et reprise simultanés d’éléments à partir de plusieurs threads.Concurrent adding and taking of items from multiple threads.

  • Capacité maximale facultative.Optional maximum capacity.

  • Opérations d’insertion et de suppression qui se bloquent quand la collection est vide ou complète.Insertion and removal operations that block when collection is empty or full.

  • Opérations « d’essai » d’insertion et de suppression qui ne se bloquent pas ou qui se bloquent pendant une période spécifiée.Insertion and removal "try" operations that do not block or that block up to a specified period of time.

  • Encapsule tout type de collection qui implémente IProducerConsumerCollection<T>Encapsulates any collection type that implements IProducerConsumerCollection<T>

  • Annulation avec jetons d’annulation.Cancellation with cancellation tokens.

  • Deux types d’énumération avec foreach (For Each en Visual Basic) :Two kinds of enumeration with foreach (For Each in Visual Basic):

    1. Énumération en lecture seule.Read-only enumeration.

    2. Énumération qui supprime des éléments à mesure qu’ils sont énumérés.Enumeration that removes items as they are enumerated.

Prise en charge de la délimitation et du blocageBounding and Blocking Support

BlockingCollection<T> prend en charge la délimitation et le blocage.BlockingCollection<T> supports bounding and blocking. La délimitation signifie que vous pouvez définir la capacité maximale de la collection.Bounding means you can set the maximum capacity of the collection. La délimitation est importante dans certains scénarios, car elle vous permet de contrôler la taille maximale de la collection en mémoire, et elle empêche les threads producteur de se déplacer trop loin avant les threads consommateur.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.

Plusieurs threads ou tâches peuvent ajouter simultanément des éléments à la collection, et si la collection atteint sa capacité maximale spécifiée, les threads producteur se bloquent jusqu’à ce qu’un élément soit supprimé.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. Plusieurs consommateurs peuvent supprimer des éléments simultanément, et si la collection devient vide, les threads consommateur se bloquent jusqu’à ce qu’un producteur ajoute un élément.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 producteur peut appeler CompleteAdding pour indiquer qu’aucun élément supplémentaire ne sera ajouté.A producing thread can call CompleteAdding to indicate that no more items will be added. Les consommateurs surveillent la propriété IsCompleted pour savoir quand la collection est vide et quand aucun autre élément ne sera ajouté.Consumers monitor the IsCompleted property to know when the collection is empty and no more items will be added. L’exemple suivant montre un BlockingCollection simple avec une capacité limitée de 100.The following example shows a simple BlockingCollection with a bounded capacity of 100. Une tâche de producteur ajoute des éléments à la collection tant qu’une certaine condition externe est remplie, puis appelle CompleteAdding.A producer task adds items to the collection as long as some external condition is true, and then calls CompleteAdding. La tâche du consommateur prend des éléments jusqu’à ce que la propriété IsCompleted ait la valeur 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)

Pour un exemple complet, consultez Guide pratique : ajouter et prendre des éléments individuellement dans un BlockingCollection.For a complete example, see How to: Add and Take Items Individually from a BlockingCollection.

Opérations de blocage temporiséTimed Blocking Operations

Dans les opérations TryAdd et TryTake de blocage temporisé sur les collections limitées, la méthode tente d’ajouter ou de prendre un élément.In timed blocking TryAdd and TryTake operations on bounded collections, the method tries to add or take an item. Si un élément est disponible, il est placé dans la variable qui a été passée par référence, et la méthode retourne la valeur true.If an item is available it is placed into the variable that was passed in by reference, and the method returns true. Si aucun élément n’est récupéré après un délai d’attente spécifié, la méthode retourne la valeur false.If no item is retrieved after a specified time-out period the method returns false. Le thread est ensuite libre d’effectuer un autre travail utile avant de réessayer d’accéder à la collection.The thread is then free to do some other useful work before trying again to access the collection. Pour un exemple d’accès à blocage temporisé, consultez le deuxième exemple de la rubrique Guide pratique : ajouter et prendre des éléments individuellement dans un BlockingCollection.For an example of timed blocking access, see the second example in How to: Add and Take Items Individually from a BlockingCollection.

Annulation d’opérations Add et TakeCancelling Add and Take Operations

Les opérations Add et Take sont généralement effectuées dans une boucle.Add and Take operations are typically performed in a loop. Vous pouvez annuler une boucle en passant un CancellationToken à la méthode TryAdd ou TryTake, puis en vérifiant la valeur de la propriété IsCancellationRequested du jeton à chaque itération.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 la valeur est true, vous pouvez, si vous le souhaitez, répondre à la demande d’annulation en nettoyant toutes les ressources et en quittant la boucle.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. L’exemple suivant montre une surcharge de TryAdd qui prend un jeton d’annulation, ainsi que le code qui l’utilise :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

Pour un exemple d’ajout de prise en charge de l’annulation, consultez le deuxième exemple de la rubrique Guide pratique : ajouter et prendre des éléments individuellement dans un 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.

Spécification du type de collectionSpecifying the Collection Type

Quand vous créez un BlockingCollection<T>, vous pouvez spécifier non seulement la capacité limitée, mais aussi le type de collection à utiliser.When you create a BlockingCollection<T>, you can specify not only the bounded capacity but also the type of collection to use. Par exemple, vous pouvez spécifier un ConcurrentQueue<T> pour un comportement premier entré, premier sorti (FIFO, First In-First Out), ou un ConcurrentStack<T> pour un comportement dernier entré, premier sorti (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. Vous pouvez utiliser n’importe quelle classe de collection qui implémente l’interface IProducerConsumerCollection<T>.You can use any collection class that implements the IProducerConsumerCollection<T> interface. Le type de collection par défaut pour BlockingCollection<T> est ConcurrentQueue<T>.The default collection type for BlockingCollection<T> is ConcurrentQueue<T>. L’exemple de code suivant montre comment créer un BlockingCollection<T> de chaînes qui possède une capacité de 1000 et qui utilise un 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 );  

Pour plus d'informations, voir Procédure : ajouter des fonctionnalités de délimitation et de blocage à une collection.For more information, see How to: Add Bounding and Blocking Functionality to a Collection.

Prise en charge d’IEnumerableIEnumerable Support

BlockingCollection<T> fournit une méthode GetConsumingEnumerable qui permet aux consommateurs d’utiliser une instruction foreach (For Each en Visual Basic) pour supprimer des éléments jusqu’à ce que la collection soit terminée, ce qui signifie qu’elle est vide et qu’aucun autre élément ne sera plus ajouté.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. Pour plus d'informations, voir Procédure : utiliser la boucle ForEach pour supprimer les éléments d’un BlockingCollection.For more information, see How to: Use ForEach to Remove Items in a BlockingCollection.

Utilisation de nombreux BlockingCollections comme un seulUsing Many BlockingCollections As One

Pour les scénarios dans lesquels un consommateur doit prendre simultanément des éléments à partir de plusieurs collections, vous pouvez créer des tableaux de BlockingCollection<T> et utiliser les méthodes statiques telles que TakeFromAny et AddToAny qui effectuent un ajout ou une prise dans n’importe laquelle des collections du tableau.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 une collection bloque, la méthode en essaie immédiatement une autre jusqu’à ce qu’elle en trouve une qui peut effectuer l’opération.If one collection is blocking, the method immediately tries another until it finds one that can perform the operation. Pour plus d'informations, voir Procédure : utiliser des tableaux de collections de blocage dans un pipeline.For more information, see How to: Use Arrays of Blocking Collections in a Pipeline.

Voir aussiSee also