Bagikan melalui


Cara: Menulis Perulangan Paralel.For dengan Variabel Rangkaian Lokal

Contoh ini menunjukkan cara menggunakan variabel rangkaian lokal untuk menyimpan dan mengambil status di setiap tugas terpisah yang dibuat oleh perulangan For. Dengan menggunakan data rangkaian lokal, Anda dapat menghindari overhead sinkronisasi sejumlah besar akses ke status bersama. Alih-alih menulis ke sumber daya bersama pada setiap perulangan, Anda menghitung dan menyimpan nilainya hingga semua perulangan untuk tugas selesai. Kemudian Anda dapat menulis hasil akhir sekali ke sumber daya bersama, atau meneruskannya ke metode lain.

Contoh

Contoh berikut memanggil metode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) untuk menghitung jumlah nilai dalam array yang berisi satu juta elemen. Nilai setiap elemen sama dengan indeksnya.

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

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

        // Use type parameter to make subtotal a long, not an int
        Parallel.For<long>(0, nums.Length, () => 0,
            (j, loop, subtotal) =>
            {
                subtotal += nums[j];
                return subtotal;
            },
            subtotal => Interlocked.Add(ref total, subtotal));

        Console.WriteLine("The total is {0:N0}", total);
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }
}
'How to: Write a Parallel.For Loop That Has Thread-Local Variables

Imports System.Threading
Imports System.Threading.Tasks

Module ForWithThreadLocal

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

        ' Use type parameter to make subtotal a Long type. Function will overflow otherwise.
        Parallel.For(Of Long)(0, nums.Length, Function() 0, Function(j, [loop], subtotal)
                                                                subtotal += nums(j)
                                                                Return subtotal
                                                            End Function, Function(subtotal) Interlocked.Add(total, subtotal))

        Console.WriteLine("The total is {0:N0}", total)
        Console.WriteLine("Press any key to exit")
        Console.ReadKey()
    End Sub

End Module

Dua parameter pertama dari setiap metode For menentukan nilai perulangan awal dan akhir. Dalam kelebihan metode ini, parameter ketiga adalah tempat Anda menginisialisasi status lokal. Dalam konteks ini, keadaan lokal berarti variabel yang masa hidupnya diperluas dari sebelum perulangan pertama dari perulangan pada rangkaian saat ini, hingga tepat setelah perulangan terakhir.

Jenis parameter ketiga adalah Func<TResult> saat TResult adalah jenis variabel yang akan menyimpan status rangkaian lokal. Jenisnya didefinisikan oleh argumen jenis generik yang disediakan saat memanggil metode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) generik, yang dalam hal ini adalah Int64. Argumen jenis memberi tahu pengompilasi jenis variabel sementara yang akan digunakan untuk menyimpan status rangkaian lokal. Dalam contoh ini, ekspresi () => 0 (atau Function() 0 dalam Visual Basic) menginisialisasi variabel rangkaian lokal ke nol. Jika argumen jenis generik adalah jenis referensi atau jenis nilai yang ditentukan pengguna, ekspresi akan terlihat seperti ini:

() => new MyClass()  
Function() new MyClass()  

Parameter keempat mendefinisikan logika perulangan. Ini harus berupa delegasi atau ekspresi lambda yang tanda tangannya ada Func<int, ParallelLoopState, long, long> di C# atau Func(Of Integer, ParallelLoopState, Long, Long) di Visual Basic. Parameter pertama adalah nilai penghitung perulangan untuk perulangan dari perulangan tersebut. Yang kedua adalah objek ParallelLoopState yang dapat digunakan untuk keluar dari perulangan; objek ini disediakan oleh kelas Parallel untuk setiap kemunculan perulangan. Parameter ketiga adalah variabel rangkaian lokal. Parameter terakhir adalah jenis pengembalian. Dalam hal ini, jenisnya adalah Int64 karena itu adalah jenis yang kita tentukan dalam argumen jenis For. Variabel tersebut diberi nama subtotal dan dikembalikan oleh ekspresi lambda. Nilai yang dikembalikan digunakan untuk menginisialisasi subtotal pada setiap perulangan dari perulangan berikutnya. Anda juga dapat menganggap parameter terakhir ini sebagai nilai yang diteruskan ke setiap perulangan, lalu diteruskan ke delegasi localFinally saat perulangan terakhir selesai.

Parameter kelima mendefinisikan metode yang dipanggil satu kali, setelah semua perulangan pada rangkaian tertentu telah selesai. Jenis argumen input lagi sesuai dengan argumen jenis dari metode For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) dan jenis yang dikembalikan oleh ekspresi lambda isi. Dalam contoh ini, nilai ditambahkan ke variabel pada cakupan kelas dalam rangkaian dengan cara yang aman dengan memanggil metode Interlocked.Add. Dengan menggunakan variabel rangkaian lokal, kami telah menghindari penulisan ke variabel kelas ini pada setiap perulangan dari perulangan.

Untuk informasi selengkapnya tentang cara menggunakan ekspresi lambda, lihat Ekspresi Lambda di PLINQ dan TPL.

Lihat juga