Para ver el artículo en inglés, active la casilla Inglés. También puede ver el texto en inglés en una ventana emergente si pasa el puntero del mouse por el texto.
Traducción
Inglés

Lambda Expressions in PLINQ and TPL

.NET Framework (current version)
 

La biblioteca TPL (Task Parallel Library, biblioteca de procesamiento paralelo basado en tareas) contiene muchos métodos que toman una de las familias de delegados System.Func<TResult> o System.Action como parámetros de entrada. Estos delegados se usan para pasar la lógica del programa personalizado al bucle, tarea o consulta paralelo. Los ejemplos de código de TPL, así como PLINQ, usan expresiones lambda para crear instancias de los delegados como bloques de código alineado. En este tema se proporciona una breve introducción a Func y Action, y se muestra cómo usar las expresiones lambda en la biblioteca TPL y PLINQ.

Nota Para obtener más información sobre los delegados en general, vea Delegados (Guía de programación de C#) y Delegados (Visual Basic). Para obtener más información sobre las expresiones lambda en C# y Visual Basic, vea Expresiones lambda (Guía de programación de C#) y Lambda (expresiones) (Visual Basic).

Un delegado Func encapsula un método que devuelve un valor. En una signatura de Func, el último parámetro de tipo, o el situado en el extremo derecho, siempre especifica el tipo de valor devuelto. Una causa común de los errores del compilador es el intento de pasar dos parámetros de entrada a System.Func<T, TResult>; de hecho, este tipo toma un único parámetro de entrada. La biblioteca de clases de .NET Framework define 17 versiones de Func: System.Func<TResult>, System.Func<T, TResult>, System.Func<T1, T2, TResult>, y así sucesivamente hasta System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>.

Un delegado System.Action encapsula un método (Sub en Visual Basic) que no devuelve ningún valor o que devuelve void. En una signatura de Action, los parámetros de tipo solamente representan parámetros de entrada. Al igual que sucede con Func, la biblioteca de clases de .NET Framework define 17 versiones de Action, desde una versión que no tiene ningún parámetro de tipo hasta una versión con 16 parámetros de tipo.

En el ejemplo siguiente del método Parallel.ForEach<TSource, TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, TLocal, TLocal>, Action<TLocal>) se muestra cómo expresar los delegados Func y Action mediante expresiones lambda.

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:
    //		http://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);
        }
    }

}
Mostrar: