Postupy: Zápis smyčky Parallel.ForEach s využitím místních proměnných oddílů

Následující příklad ukazuje, jak napsat metodu ForEach , která používá proměnné partition-local. Při provedení smyčky ForEach dochází k rozdělení kolekce prostředků na několik oddílů. Každý oddíl má vlastní kopii místní proměnné oddílu. Místní proměnná oddílu se podobá místní proměnné vlákna s tím rozdílem, že na jednom vlákně může běžet více oddílů.

Kód a parametry uvedené v tomto příkladu se velmi podobají příslušné metodě For. Další informace naleznete v tématu Postupy: Zápis parallel.For Loop s vlákny místní proměnné.

Chcete-li ve smyčce použít místní proměnnou oddílu ForEach , musíte volat jedno z přetížení metody, které přebírá dva parametry typu. První parametr typu , TSource, určuje typ zdrojového elementu a druhý typ parametr, TLocalurčuje typ partition-local proměnné.

Příklad

Následující příklad volá Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) přetížení pro výpočet součtu pole jednoho milionu prvků. Toto přetížení má čtyři parametry:

  • source, což je zdroj dat. Musí implementovat IEnumerable<T>. Zdroj dat v našem příkladu je objekt jednoho milionu členů IEnumerable<Int32> vrácený metodou Enumerable.Range .

  • localInitnebo funkci, která inicializuje místní proměnnou oddílu. Tato funkce se volá jednou pro každý oddíl, ve kterém se Parallel.ForEach operace provede. Náš příklad inicializuje místní proměnnou oddílu na nulu.

  • bodyFunc<T1,T2,T3,TResult>, která je vyvolána paralelní smyčkou pro každou iteraci smyčky. Jeho podpis je Func\<TSource, ParallelLoopState, TLocal, TLocal>. Zadáte kód pro delegáta a smyčka předává vstupní parametry, které jsou:

    • Aktuální prvek IEnumerable<T>.

    • Proměnná ParallelLoopState , kterou můžete použít v kódu delegáta k prozkoumání stavu smyčky.

    • Místní proměnná oddílu.

    Váš delegát vrátí místní proměnnou oddílu, která se pak předá další iteraci smyčky, která se provede v daném oddílu. Každý oddíl smyčky udržuje samostatnou instanci této proměnné.

    V tomto příkladu delegát přidá hodnotu každého celého čísla do místní proměnné oddílu, která udržuje průběžný součet hodnot celočíselných prvků v tomto oddílu.

  • localFinallyAction<TLocal>, delegát, který Parallel.ForEach vyvolá, když se operace smyčky v každém oddílu dokončily. Metoda Parallel.ForEach předává delegáta Action<TLocal> konečnou hodnotu proměnné partition-local pro tento oddíl smyčky a zadáte kód, který provede požadovanou akci pro kombinování výsledku z tohoto oddílu s výsledky z ostatních oddílů. Tento delegát lze vyvolat souběžně s několika úkoly. Z tohoto důvodu příklad používá metodu Interlocked.Add(Int32, Int32) k synchronizaci přístupu k total proměnné. Vzhledem k tomu, že delegát je typu Action<T>, neexistuje žádná návratová hodnota.

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

Viz také