Partager via


Expressions lambda en PLINQ et dans la bibliothèque parallèle de tâches

La bibliothèque parallèle de tâches contient de nombreuses méthodes qui prennent l'une des familles de délégués System.Func<TResult> ou System.Action comme paramètres d'entrée. Vous utilisez ces délégués pour passer votre logique de programme personnalisée à la boucle, tâche ou requête parallèle. Les exemples de code de TPL et PLINQ utilisent des expressions lambda pour créer des instances de ces délégués sous forme de blocs de code incorporé. Cette rubrique fournit une brève introduction à Func et Action et vous montre comment utiliser des expressions lambda dans la bibliothèque parallèle de tâches et PLINQ.

Remarque   Pour plus d'informations sur les délégués en général, consultez Délégués (guide de programmation C#) et Délégués (Visual Basic). Pour plus d'informations sur les expressions lambda en C# et Visual Basic, consultez Expressions lambda (Guide de programmation C#) et Expressions lambda (Visual Basic).

Délégué Func

Un délégué Func encapsule une méthode qui retourne une valeur. Dans une signature Func, le dernier ou le plus à droite des paramètres de type spécifie toujours le type de retour. Une cause fréquente entraînant des erreurs du compilateur est la tentative de passer deux paramètres d'entrée au type System.Func<T, TResult> ; en fait ce type prend en charge un seul paramètre d'entrée. La bibliothèque de classes .NET Framework définit 17 versions de Func : System.Func<TResult>, System.Func<T, TResult>, System.Func<T1, T2, TResult> et ainsi de suite, jusqu'à System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>.

Délégué Action

Un délégué System.Action encapsule une méthode (Sub en Visual Basic) qui ne retourne pas de valeur ou retourne void. Dans une signature de type Action, les paramètres de type représentent uniquement des paramètres d'entrée. Comme pour Func, la bibliothèque de classes .NET Framework définit 17 versions d'Action, d'une version sans paramètre de type jusqu'à une version avec 16 paramètres de type.

Exemple

L'exemple suivant de la méthode Parallel.ForEach<TSource, TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, TLocal, TLocal>, Action<TLocal>) indique comment exprimer les délégués Func et Action à l'aide d'expressions lambda.

Imports System.Threading
Imports System.Threading.Tasks
Module ForEachDemo

    ' Demonstrated features:
    '   Parallel.ForEach()
    '   Thread-local state
    ' Expected results:
    '   This example sums up the elements of an int[] in parallel.
    '   Each thread maintains a local sum. When a thread is initialized, that local sum is set to 0.
    '   On every iteration the current element is added to the local sum.
    '   When a thread is done, it safely adds its local sum to the global sum.
    '   After the loop is complete, the global sum is printed out.
    ' Documentation:
    '   https://msdn.microsoft.com/en-us/library/dd990270(VS.100).aspx
    Private Sub ForEachDemo()
        ' The sum of these elements is 40.
        Dim input As Integer() = {4, 1, 6, 2, 9, 5, _
        10, 3}
        Dim sum As Integer = 0

        Try
            ' source collection
            Parallel.ForEach(input,
                             Function()
                                 ' thread local initializer
                                 Return 0
                             End Function,
                             Function(n, loopState, localSum)
                                 ' body
                                 localSum += n
                                 Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum)
                                 Return localSum
                             End Function,
                             Sub(localSum)
                                 ' thread local aggregator
                                 Interlocked.Add(sum, localSum)
                             End Sub)

            Console.WriteLine(vbLf & "Sum={0}", sum)
        Catch e As AggregateException
            ' No exception is expected in this example, but if one is still thrown from a task,
            ' it will be wrapped in AggregateException and propagated to the main thread.
            Console.WriteLine("Parallel.ForEach has thrown an exception. THIS WAS NOT EXPECTED." & vbLf & "{0}", e)
        End Try
    End Sub


End Module
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

class ForEachWithThreadLocal
{
    // Demonstrated features:
    //      Parallel.ForEach()
    //      Thread-local state
    // Expected results:
    //      This example sums up the elements of an int[] in parallel.
    //      Each thread maintains a local sum. When a thread is initialized, that local sum is set to 0.
    //      On every iteration the current element is added to the local sum.
    //      When a thread is done, it safely adds its local sum to the global sum.
    //      After the loop is complete, the global sum is printed out.
    // Documentation:
    //      https://msdn.microsoft.com/en-us/library/dd990270(VS.100).aspx
    static void Main()
    {
        // The sum of these elements is 40.
        int[] input = { 4, 1, 6, 2, 9, 5, 10, 3 };
        int sum = 0;

        try
        {
            Parallel.ForEach(
                    input,                          // source collection
                    () => 0,                         // thread local initializer
                    (n, loopState, localSum) =>      // body
                    {
                        localSum += n;
                        Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum);
                        return localSum;
                    },
                    (localSum) => Interlocked.Add(ref sum, localSum)                 // thread local aggregator
                );

            Console.WriteLine("\nSum={0}", sum);
        }
        // No exception is expected in this example, but if one is still thrown from a task,
        // it will be wrapped in AggregateException and propagated to the main thread.
        catch (AggregateException e)
        {
            Console.WriteLine("Parallel.ForEach has thrown an exception. THIS WAS NOT EXPECTED.\n{0}", e);
        }
    }

}

Voir aussi

Concepts

Programmation parallèle dans le .NET Framework