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.