Aracılığıyla paylaş


Nasıl Yapılır: Thread-Local Değişkenleriyle Parallel.For Döngüsü Yazma

Bu örnek, For döngüsü tarafından oluşturulan her ayrı görevdeki durumu depolamak ve almak için iş parçacığına özgü değişkenlerin nasıl kullanılacağını gösterir. İş parçacığına özgü verileri kullanarak, paylaşılan duruma yapılan çok sayıda erişimin senkronizasyon yükünden kaçınabilirsiniz. Her yinelemede paylaşılan bir kaynağa yazmak yerine, görevin tüm yinelemeleri tamamlanana kadar değeri hesaplar ve depolarsınız. Ardından son sonucu paylaşılan kaynağa bir kez yazabilir veya başka bir yönteme geçirebilirsiniz.

Örnek

Aşağıdaki örnek, bir milyon öğe içeren bir dizideki değerlerin toplamını hesaplamak için yöntemini çağırır For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) . Her öğenin değeri kendi dizinine eşittir.

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

Her For yöntemin ilk iki parametresi, başlangıç ve bitiş yineleme değerlerini belirtir. Bu yöntemin aşırı yüklemesi içinde, üçüncü parametre yerel durumunuzu başlattığınız yerdir. Bu bağlamda yerel durum, yaşam süresi geçerli iş parçacığındaki döngünün ilk yinelemesinden hemen öncesinden son yinelemeden hemen sonrasına kadar uzanan bir değişken anlamına gelir.

Üçüncü parametrenin türü bir Func<TResult> türüdür; burada TResult, iş parçacığı yerel durumunu depolayacak değişkenin türüdür. Türü, genel For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) yöntem çağrılırken sağlanan Int64 tür bağımsız değişkeni tarafından tanımlanır, bu durumda ise Int64'dir. Tür bağımsız değişkeni, derleyiciye iş parçacığı yerel durumunu depolamak için kullanılacak değişkenin geçici türünü bildirir. Bu örnekte, ifade () => 0 (veya Function() 0 Visual Basic'te) iş parçacığı yerel değişkenini sıfır olarak başlatır. Genel tür bağımsız değişkeni bir başvuru türü veya kullanıcı tanımlı değer türüyse, ifade şöyle görünür:

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

Dördüncü parametre döngü mantığını tanımlar. C#'ta Func<int, ParallelLoopState, long, long> veya Visual Basic'te Func(Of Integer, ParallelLoopState, Long, Long) şeklinde bir imzaya sahip bir delege ya da lambda ifadesi olmalıdır. İlk parametre, döngünün bu yinelemesi için döngü sayacının değeridir. İkincisi, döngüden çıkmak için kullanılabilecek bir ParallelLoopState nesnedir; bu nesne sınıfı tarafından döngünün Parallel her oluşumuna sağlanır. Üçüncü parametre, iş parçacığı yerel değişkenidir. Son parametre dönüş türüdür. Bu durumda tür, For tür bağımsız değişkeninde belirttiğimiz Int64 türüdür. Bu değişken adlandırılır subtotal ve lambda ifadesi tarafından döndürülür. Döngünün sonraki her yinelemesinde subtotal'ı başlatmak için dönüş değeri kullanılır. Bu son parametreyi, her yinelemeye geçirilen ve son yineleme tamamlandığında temsilciye localFinally geçirilen bir değer olarak da düşünebilirsiniz.

Beşinci parametre, belirli bir iş parçacığındaki tüm yinelemeler tamamlandıktan sonra bir kez çağrılan yöntemi tanımlar. Giriş bağımsız değişkeninin türü, For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) yönteminin tür bağımsız değişkenine ve gövde lambda ifadesinin döndürdüğü türe yine karşılık gelir. Bu örnekte, yöntemini çağırarak Interlocked.Add, sınıf kapsamındaki bir değişkene iş parçacığı güvenliği sağlayarak değer ekler. İş parçacığı yerel değişkenini kullanarak döngünün her yinelemesinde bu sınıf değişkenine yazmaktan kaçındık.

Lambda ifadelerini kullanma hakkında daha fazla bilgi için bkz. PLINQ ve TPL'de Lambda İfadeleri.

Ayrıca bkz.