Aracılığıyla paylaş


Nasıl yapılır: Bölüm yerel değişkenleriyle Parallel.ForEach döngüsü yazma

Aşağıdaki örnek, bölüm yerel değişkenlerini kullanan bir ForEach yönteminin nasıl yazıldığını gösterir. bir ForEach döngüsü yürütürken, kaynak koleksiyonunu birden çok bölüme böler. Her bölümün kendi partition-local değişkeni kopyası vardır. Bölüm yerel değişkeni, iş parçacığı yerel değişkenine benzer, ancak tek bir iş parçacığında birden çok bölüm çalıştırılabilir.

Bu örnekteki kod ve parametreler, karşılık gelen For yöntemine benzer. Daha fazla bilgi için bkz. Nasıl yapılır: Thread-Local Değişkenleri ile Parallel.For Döngüsü Yazma.

bir ForEach döngüsünde partition-local değişkenini kullanmak için iki tür parametre alan yöntem aşırı yüklemelerinden birini çağırmanız gerekir. İlk tür parametresi TSource, kaynak öğenin türünü, TLocalikinci tür parametresi ise partition-local değişkeninin türünü belirtir.

Örnek

Aşağıdaki örnek, bir milyon öğeden oluşan bir dizinin toplamını hesaplamak için Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) aşırı yüklemesini çağırır. Bu aşırı yükleme dört parametreye sahiptir:

  • sourceveri kaynağıdır. IEnumerable<T>uygulamalıdır. Örneğimizdeki veri kaynağı, Enumerable.Range yöntemi tarafından döndürülen bir milyon üye IEnumerable<Int32> nesnesidir.

  • localInitveya da bölüme özgü değişkeni başlatan işlev. Bu işlev, Parallel.ForEach işleminin yürütüldiği her bölüm için bir kez çağrılır. Örneğimiz partition-local değişkenini sıfır olarak başlatır.

  • body, döngünün her yinelemesinde paralel döngü tarafından çağrılan bir Func<T1,T2,T3,TResult>. İmzası Func\<TSource, ParallelLoopState, TLocal, TLocal>. Temsilci için kodu sağlarsınız ve döngü, giriş parametrelerini iletir; bunlar:

    • IEnumerable<T>'nun geçerli öğesi.

    • Döngünün durumunu incelemek için temsilcinizin kodunda kullanabileceğiniz bir ParallelLoopState değişkeni.

    • Partition-local değişkeni.

    Temsilciniz partition-local değişkenini döndürür ve bu değişken daha sonra ilgili bölümde yürütülen döngünün bir sonraki yinelemesine geçirilir. Her döngü bölümü bu değişkenin ayrı bir örneğini tutar.

    Örnekte, temsilci her tamsayı değerini partition-local değişkenine ekler ve bu da bu bölümdeki tamsayı öğelerinin değerlerinin değişen toplamını tutar.

  • localFinally, her bir bölümdeki döngü işlemlerinin tamamlanmasının ardından Parallel.ForEach'nin çağırdığı bir Action<TLocal> temsilcisidir. Parallel.ForEach yöntemi, bu döngü bölümü için bölüm yerel değişkeninin son değerini Action<TLocal> temsilcinize geçirir ve bu bölümden elde edilen sonucu diğer bölümlerden elde edilen sonuçlarla birleştirmek için gerekli eylemi gerçekleştiren kodu sağlarsınız. Bu temsilci birden çok görev tarafından eşzamanlı olarak çağrılabilir. Bu nedenle örnek, total değişkenine erişimi eşitlemek için Interlocked.Add(Int32, Int32) yöntemini kullanır. Temsilci türü bir Action<T>olduğundan, dönüş değeri yoktur.

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 {total:N0}");
    }
}
// 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

Ayrıca bkz.