Sdílet prostřednictvím


Postupy: Zápis smyčky Parallel.For pomocí proměnných v místním vláknu

Tento příklad ukazuje, jak pomocí místních proměnných vláken ukládat a načítat stav v jednotlivých samostatných úlohách vytvořených smyčkou For . Pomocí místních dat vláken se můžete vyhnout režii synchronizace velkého počtu přístupů ke sdílenému stavu. Místo zápisu do sdíleného prostředku v každé iteraci vypočítáte a uložíte hodnotu, dokud nebudou dokončeny všechny iterace úkolu. Konečný výsledek pak můžete jednou napsat do sdíleného prostředku nebo ho předat jiné metodě.

Příklad

Následující příklad volá metodu For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) k výpočtu součtu hodnot v matici, která obsahuje jeden milion prvků. Hodnota každého prvku je rovna jeho indexu.

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

První dva parametry každé For metody určují počáteční a koncové hodnoty iterace. V tomto přetížení metody je třetí parametr, kde inicializujete místní stav. V tomto kontextu místní stav znamená proměnnou, jejíž životnost se prodlužuje těsně před první iterací smyčky v aktuálním vlákně, až po poslední iteraci.

Typ třetího parametru je Func<TResult>TResult typ proměnné, která uloží místní stav vlákna. Jeho typ je definován obecný typ argument zadaný při volání obecné For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) metody, což je Int64v tomto případě . Argument typu říká kompilátoru typ dočasné proměnné, která bude použita k uložení stavu thread-local. V tomto příkladu výraz () => 0 (nebo Function() 0 v jazyce Visual Basic) inicializuje lokální proměnnou vlákna na nulu. Pokud je argument obecného typu odkaz nebo uživatelem definovaný typ hodnoty, výraz by vypadal takto:

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

Čtvrtý parametr definuje logiku smyčky. Musí to být výraz delegáta nebo lambda, jehož podpis je Func<int, ParallelLoopState, long, long> v jazyce C# nebo Func(Of Integer, ParallelLoopState, Long, Long) v jazyce Visual Basic. Prvním parametrem je hodnota čítače smyčky pro tuto iteraci smyčky. Druhá je ParallelLoopState objekt, který lze použít k přerušení smyčky; tento objekt je poskytován Parallel třídou pro každý výskyt smyčky. Třetí parametr je místní proměnná vlákna. Posledním parametrem je návratový typ. V tomto případě je Int64 typ, protože je to typ, který jsme zadali v argumentu For typu. Tato proměnná je pojmenovaná subtotal a je vrácena výrazem lambda. Vrácená hodnota se používá k inicializaci subtotal pro každou následnou iteraci smyčky. Tento poslední parametr si také můžete představit jako hodnotu, která se předá každé iteraci, a pak delegáta localFinally předá po dokončení poslední iterace.

Pátý parametr definuje metodu, která se volá jednou, po dokončení všech iterací v určitém vlákně. Typ vstupního argumentu znovu odpovídá argumentu For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) typu metody a typu vráceného výrazem body lambda. V tomto příkladu se hodnota přidá do proměnné v oboru třídy bezpečným způsobem voláním Interlocked.Add metody. Pomocí lokální proměnné vlákna jsme se vyhnuli zápisu do této proměnné třídy při každé iteraci smyčky.

Další informace o použití výrazů lambda naleznete v tématu Výrazy lambda v PLINQ a TPL.

Viz také