Share via


在 PLINQ 和 TPL 中的 Lambda 表达式

任务并行库 (TPL) 包含许多方法,这些方法采用委托的 System.Func<TResult>System.Action 系列中的其中一个作为输入参数。 您使用这些委托将自定义程序逻辑传入至并行循环、任务或查询。 TPL 以及 PLINQ 的代码示例使用 lambda 表达式以内联代码块的形式创建这些委托的实例。 本主题简要介绍 Func 和 Action,并演示如何在任务并行库和 PLINQ 中使用 lambda 表达式。

注意   有关委托的更多常规信息,请参见委托(C# 编程指南)委托 (Visual Basic)。 有关 C# 和 Visual Basic 中的 lambda 表达式的更多信息,请参见 Lambda 表达式(C# 编程指南)Lambda 表达式 (Visual Basic)

Func 委托

Func 委托封装一个返回值的方法。 在 Func 签名中,最后或最右侧的类型参数始终指定返回类型。 编译器错误的一个常见原因是尝试将两个输入参数传递给一个 System.Func<T, TResult>;实际上,此类型仅采用一个输入参数。 Framework 类库定义了 17 个版本的 Func:System.Func<TResult>System.Func<T, TResult>System.Func<T1, T2, TResult>,诸如此类直至 System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>

Action 委托

System.Action 委托封装一个不返回值的方法(Visual Basic 中为 Sub),或返回 void。 在 Action 类型签名中,类型参数仅表示输入参数。 像 Func 一样,Framework 类库定义了 17 个版本的 Action,从没有类型参数的版本直至具有 16 个类型参数的版本。

示例

Parallel.ForEach<TSource, TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource, ParallelLoopState, TLocal, TLocal>, Action<TLocal>) 方法的以下示例演示如何使用 lambda 表达式表达 Func 和 Action 委托。

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);
        }
    }

}

请参见

概念

.NET Framework 中的并行编程