分享方式:


PLINQ 和 TPL 中的 Lambda 運算式

工作平行程式庫 (TPL) 包含了許多會採用其中一個委派的 System.Func<TResult>System.Action 系列作為輸入參數的方法。 您可以使用這些委派將您自訂的程式邏輯傳遞到平行迴圈、工作或查詢中。 TPL 以及 PLINQ 的程式碼範例會使用 lambda 運算式來建立這些委派的執行個體,以作為內嵌程式碼區塊。 本主題將簡單介紹 Func 與 Action,並說明如何在工作平行程式庫和 PLINQ 中使用 lambda 運算式。

注意

一般來說,如需委派的詳細資訊,請參閱委派 (C#) 和委派 (Visual Basic)。 如需 C# 和 Visual Basic 中之 lambda 運算式的詳細資訊,請參閱 Lambda 運算式Lambda 運算式

Func 委派

Func 委派所封裝的方法會傳回值。 在 Func 簽章中,最後一個或最右邊的型別參數一律會指定傳回型別。 其中一個常見的編譯器錯誤原因是嘗試將兩個輸入參數傳入 System.Func<T,TResult>;事實上,此型別只會採用一個輸入參數。 .NET 定義 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) 不會傳回值。 在 Action 型別簽章中,型別參數只代表輸入參數。 就像 Func,.NET 定義 17 個版本的 Action,從不具型別參數的版本,一直到具有 16 個型別參數的版本。

範例

下列 Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) 方法的範例顯示如何透過使用 Lambda 運算式來表達 Func 與 Action 委派。

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/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);
        }
    }
}
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:
    '   http://msdn.microsoft.com/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

另請參閱