Delen via


Procedure: Een Parallel.ForEach-lus schrijven met partitie-lokale variabelen

In het volgende voorbeeld ziet u hoe u een ForEach methode schrijft die gebruikmaakt van partitie-lokale variabelen. Wanneer een ForEach lus wordt uitgevoerd, verdeelt deze de bronverzameling in meerdere partities. Elke partitie heeft een eigen kopie van de partitie-lokale variabele. Een partitie-lokale variabele is vergelijkbaar met een thread-lokale variabele, behalve dat meerdere partities op één thread kunnen worden uitgevoerd.

De code en parameters in dit voorbeeld lijken sterk op de bijbehorende For methode. Zie How to: Write a Parallel.For Loop with Thread-Local Variables voor meer informatie.

Als u een partitie-lokale variabele in een ForEach lus wilt gebruiken, moet u een van de overbelastingen van de methode aanroepen die twee typeparameters gebruiken. De eerste typeparameter, TSourcegeeft het type van het bronelement en de tweede typeparameter, TLocalgeeft het type van de partitie-lokale variabele op.

Opmerking

In het volgende voorbeeld wordt de Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) overbelasting aanroepen om de som van een matrix van één miljoen elementen te berekenen. Deze overbelasting heeft vier parameters:

  • source, dit is de gegevensbron. Het moet worden geïmplementeerd IEnumerable<T>. De gegevensbron in ons voorbeeld is het miljoen lidobject IEnumerable<Int32> dat door de Enumerable.Range methode wordt geretourneerd.

  • localInitof de functie waarmee de partitie-lokale variabele wordt geïnitialiseerd. Deze functie wordt eenmaal aangeroepen voor elke partitie waarin de Parallel.ForEach bewerking wordt uitgevoerd. In ons voorbeeld wordt de partitie-lokale variabele geïnitialiseerd tot nul.

  • body, een Func<T1,T2,T3,TResult> die wordt aangeroepen door de parallelle lus op elke iteratie van de lus. De handtekening is Func\<TSource, ParallelLoopState, TLocal, TLocal>. U geeft de code voor de gemachtigde op en de lus geeft de invoerparameters door. Dit zijn:

    • Het huidige element van de IEnumerable<T>.

    • Een ParallelLoopState variabele die u in de code van uw gedelegeerde kunt gebruiken om de status van de lus te onderzoeken.

    • De partitie-lokale variabele.

    De gedelegeerde retourneert de partitie-lokale variabele, die vervolgens wordt doorgegeven aan de volgende iteratie van de lus die in die specifieke partitie wordt uitgevoerd. Elke luspartitie onderhoudt een afzonderlijk exemplaar van deze variabele.

    In het voorbeeld voegt de gedelegeerde de waarde van elk geheel getal toe aan de partitie-lokale variabele, die een actief totaal van de waarden van de gehele elementen in die partitie onderhoudt.

  • localFinally, een Action<TLocal> gemachtigde die de aanroept Parallel.ForEach wanneer de lusbewerkingen in elke partitie zijn voltooid. De Parallel.ForEach methode geeft de Action<TLocal> gedelegeerde de uiteindelijke waarde van de partitie-lokale variabele voor deze luspartitie door en u geeft de code op waarmee de vereiste actie wordt uitgevoerd voor het combineren van het resultaat van deze partitie met de resultaten van de andere partities. Deze gemachtigde kan gelijktijdig worden aangeroepen door meerdere taken. Daarom gebruikt het voorbeeld de methode om de Interlocked.Add(Int32, Int32) toegang tot de total variabele te synchroniseren. Omdat het type gemachtigde een Action<T>is, is er geen retourwaarde.

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

Zie ook