Bagikan melalui


Cara: Menulis Perulangan Parallel.ForEach dengan variabel partisi-lokal

Contoh berikut menunjukkan cara menulis metode ForEach yang menggunakan variabel partisi-local. Ketika perulangan ForEach mengeksekusi, ia membagi koleksi sumbernya menjadi beberapa partisi. Setiap partisi memiliki salinan variabel partisi-lokal sendiri. Variabel partisi-lokal mirip dengan variabel utas-lokal, kecuali bahwa beberapa partisi dapat berjalan pada utas tunggal.

Kode dan parameter dalam contoh ini sangat menyerupai metode For yang sesuai. Untuk informasi selengkapnya, lihat Cara: Menulis Perulangan Paralel.For dengan Variabel Utas-Lokal.

Untuk menggunakan variabel partitsi-lokal dalam perulangan ForEach, Anda harus memanggil salah satu kelebihan beban metode yang mengambil dua parameter jenis. Parameter jenis pertama, TSource, menentukan jenis elemen sumber, dan parameter jenis kedua, TLocal, menentukan jenis variabel partisi-lokal.

Contoh

Contoh berikut memanggil kelebihan beban Parallel.ForEach<TSource,TLocal>(IEnumerable<TSource>, Func<TLocal>, Func<TSource,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) untuk menghitung jumlah array dari satu juta elemen. Kelebihan beban ini memiliki empat parameter:

  • source, yang merupakan sumber data. Ini harus mengimplementasikan IEnumerable<T>. Sumber data dalam contoh kami adalah satu juta objek anggota IEnumerable<Int32> yang dikembalikan oleh metode Enumerable.Range.

  • localInit, atau fungsi yang menginisialisasi variabel partisi-lokal. Fungsi ini dipanggil sekali untuk setiap partisi tempat operasi Parallel.ForEach dijalankan. Contoh kami menginisialisasi variabel partisi-lokal ke nol.

  • body, a Func<T1,T2,T3,TResult> yang dipanggil oleh perulangan paralel pada setiap iterasi perulangan. Tanda tangannya adalah Func\<TSource, ParallelLoopState, TLocal, TLocal>. Anda menyediakan kode untuk delegasi, dan perulangan melewati parameter input, yaitu:

    • Elemen saat ini dari IEnumerable<T>.

    • Variabel ParallelLoopState yang dapat Anda gunakan dalam kode delegasi Anda untuk memeriksa status perulangan.

    • Variabel partisi-lokal.

    Delegasi Anda mengembalikan variabel partisi-lokal, yang kemudian diteruskan ke perulangan berikutnya dari pengulangan yang dijalankan dalam partisi tertentu. Setiap partisi perulangan mempertahankan instans terpisah dari variabel ini.

    Dalam contoh ini, delegasi menambahkan nilai setiap bilangan bulat ke variabel partisi-lokal, yang mempertahankan total nilai elemen bilangan bulat yang berjalan dalam partisi tersebut.

  • localFinally, delegasi Action<TLocal> yang dipanggil Parallel.ForEach ketika operasi perulangan di setiap partisi telah selesai. Metode Parallel.ForEach ini meneruskan delegasi Action<TLocal> Anda nilai akhir variabel partisi-lokal untuk partisi perulangan ini, dan Anda memberikan kode yang melakukan tindakan yang diperlukan untuk menggabungkan hasil dari partisi ini dengan hasil dari partisi lain. Delegasi ini dapat dipanggil secara bersamaan oleh beberapa tugas. Karena itu, contoh ini menggunakan metode Interlocked.Add(Int32, Int32) untuk menyinkronkan akses ke variabel total. Karena jenis delegasi adalah Action<T>, tidak ada nilai yang dikembalikan.

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

Lihat juga