Share via


Anvisningar: Skriva en Parallel.ForEach-loop med partitionslokala variabler

I följande exempel visas hur du skriver en ForEach metod som använder partitionslokala variabler. När en ForEach loop körs delar den upp sin källsamling i flera partitioner. Varje partition har en egen kopia av den partitionslokala variabeln. En partitionslokal variabel liknar en trådlokal variabel, förutom att flera partitioner kan köras på en enda tråd.

Koden och parametrarna i det här exemplet liknar den motsvarande For metoden. Mer information finns i How to: Write a Parallel.For Loop with Thread-Local Variables .For Loop with Thread-Local Variables .For Loop with Thread-Local Variables (Så här skriver du en parallell.For-loop med trådlokala variabler).

Om du vill använda en partitionslokal variabel i en ForEach loop måste du anropa en av de metodöverlagringar som tar två typparametrar. Den första typparametern, TSource, anger typen av källelement och den andra typparametern, TLocal, anger typen av den partitionslokala variabeln.

Exempel

I följande exempel anropas överlagringen Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) för att beräkna summan av en matris med en miljon element. Den här överlagringen har fyra parametrar:

  • source, som är datakällan. Den måste implementera IEnumerable<T>. Datakällan i vårt exempel är det en miljon medlemsobjekt IEnumerable<Int32> som returneras av Enumerable.Range metoden.

  • localIniteller funktionen som initierar den partitionslokala variabeln. Den här funktionen anropas en gång för varje partition där åtgärden Parallel.ForEach körs. Vårt exempel initierar den partitionslokala variabeln till noll.

  • body, en Func<T1,T2,T3,TResult> som anropas av den parallella loopen på varje iteration av loopen. Dess signatur är Func\<TSource, ParallelLoopState, TLocal, TLocal>. Du anger koden för ombudet och loopen skickas i indataparametrarna, som är:

    • Det aktuella elementet i IEnumerable<T>.

    • En ParallelLoopState variabel som du kan använda i ombudets kod för att undersöka loopens tillstånd.

    • Den partitionslokala variabeln.

    Ombudet returnerar den partitionslokala variabeln, som sedan skickas till nästa iteration av loopen som körs i den specifika partitionen. Varje looppartition har en separat instans av den här variabeln.

    I exemplet lägger ombudet till värdet för varje heltal i den partitionslokala variabeln, som upprätthåller en löpande summa av värdena för heltalselementen i partitionen.

  • localFinally, ett Action<TLocal> ombud som Parallel.ForEach anropas när loopningsåtgärderna i varje partition har slutförts. Metoden Parallel.ForEach skickar det Action<TLocal> slutliga värdet för den partitionslokala variabeln för den här looppartitionen och du anger den kod som utför den nödvändiga åtgärden för att kombinera resultatet från den här partitionen med resultatet från de andra partitionerna. Det här ombudet kan anropas samtidigt av flera uppgifter. På grund av detta använder Interlocked.Add(Int32, Int32) exemplet metoden för att synkronisera åtkomsten till variabeln total . Eftersom ombudstypen är en Action<T>finns det inget returvärde.

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        int[] nums = Enumerable.Range(0, 1000000).ToArray();
        long total = 0;

        // First type parameter is the type of the source elements
        // Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach<int, long>(
            nums, // source collection
            () => 0, // method to initialize the local variable
            (j, loop, subtotal) => // method invoked by the loop on each iteration
            {
                subtotal += j; //modify local variable
                return subtotal; // value to be passed to next iteration
            },
            // Method to be executed when each partition has completed.
            // finalResult is the final value of subtotal for a particular partition.
            (finalResult) => Interlocked.Add(ref total, finalResult));

        Console.WriteLine("The total from Parallel.ForEach is {0:N0}", total);
    }
}
// The example displays the following output:
//        The total from Parallel.ForEach is 499,999,500,000
' How to: Write a Parallel.ForEach Loop That Has Thread-Local Variables

Imports System.Threading
Imports System.Threading.Tasks

Module ForEachThreadLocal
    Sub Main()

        Dim nums() As Integer = Enumerable.Range(0, 1000000).ToArray()
        Dim total As Long = 0

        ' First type parameter is the type of the source elements
        ' Second type parameter is the type of the thread-local variable (partition subtotal)
        Parallel.ForEach(Of Integer, Long)(nums, Function() 0,
                                           Function(elem, loopState, subtotal)
                                               subtotal += elem
                                               Return subtotal
                                           End Function,
                                            Sub(finalResult)
                                                Interlocked.Add(total, finalResult)
                                            End Sub)

        Console.WriteLine("The result of Parallel.ForEach is {0:N0}", total)
    End Sub
End Module
' The example displays the following output:
'       The result of Parallel.ForEach is 499,999,500,000

Se även