Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a példa bemutatja, hogyan tárolhatja és lekérheti az állapotot a ciklus által létrehozott különálló feladatokban szál-helyi változók használatával For . A szálalapú adatok használatával elkerülheti a nagy számú hozzáférés szinkronizálásának többletterhelését a megosztott állapothoz. Ahelyett, hogy az egyes iterációkban megosztott erőforrásba ír, kiszámítja és tárolja az értéket, amíg a tevékenység összes iterációja be nem fejeződik. Ezután egyszer megírhatja a végeredményt a megosztott erőforrásba, vagy átadhatja egy másik metódusnak.
Példa
Az alábbi példa egy For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) egymillió elemet tartalmazó tömb értékeinek összegének kiszámítására hívja meg a metódust. Az egyes elemek értéke megegyezik az indexével.
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
Minden metódus első két paramétere For határozza meg a kezdő és záró iterációs értékeket. A metódus ezen túlterhelése esetén a harmadik paraméter az, ahol inicializálja a helyi állapotot. Ebben az összefüggésben a helyi állapot azt a változót jelenti, amelynek élettartama az aktuális szál ciklusának első iterációja előtt, az utolsó iteráció utánra terjed ki.
A harmadik paraméter Func<TResult>TResult
típusa a szál helyi állapotát tároló változó típusa. Típusát az általános metódus meghívásakor For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) megadott általános típusargumentum határozza meg, amely ebben az esetben az Int64. A típusargumentum tájékoztatja a fordítót a szál helyi állapotának tárolására használt ideiglenes változó típusáról. Ebben a példában a kifejezés () => 0
(vagy Function() 0
a Visual Basicben) nullára inicializálja a szál-helyi változót. Ha az általános típusargumentum hivatkozástípus vagy felhasználó által definiált értéktípus, a kifejezés a következőképpen fog kinézni:
() => new MyClass()
Function() new MyClass()
A negyedik paraméter határozza meg a hurok logikáját. Delegált vagy lambda kifejezésnek kell lennie, amelynek szignatúrája Func<int, ParallelLoopState, long, long>
C# nyelven vagy Func(Of Integer, ParallelLoopState, Long, Long)
a Visual Basic nyelven. Az első paraméter a hurok adott iterációjának hurokszámlálójának értéke. A második egy ParallelLoopState objektum, amely a hurokból való kibontásra használható; ezt az objektumot az Parallel osztály biztosítja a hurok minden előfordulásához. A harmadik paraméter a szál helyi változója. Az utolsó paraméter a visszatérési típus. Ebben az esetben a típus Int64, mert ez az a típus, amelyet a For típusargumentumban adtunk meg. Ennek a változónak a neve subtotal
, és a lambda kifejezés adja vissza. A visszatérési értéket használják a subtotal
inicializálására a ciklus minden további iterációján. Azt is gondolhatja, hogy ez az utolsó paraméter egy olyan érték, amelyet átad minden egyes iterációnak, majd az utolsó iteráció befejezésekor átadja a localFinally
delegáltnak.
Az ötödik paraméter határozza meg az egyszer meghívott metódust, miután az adott szál összes iterációja befejeződött. A bemeneti argumentum típusa ismét megfelel a metódus típusargumentumának For<TLocal>(Int32, Int32, Func<TLocal>, Func<Int32,ParallelLoopState,TLocal,TLocal>, Action<TLocal>) és a lambda törzskifejezés által visszaadott típusnak. Ebben a példában az érték az osztály hatókörében lévő változóhoz lesz hozzáadva szálbiztos módon a Interlocked.Add metódus meghívásával. A szálhoz kötött változó használatával elkerültük ennek az osztályváltozónak az írását a ciklus minden iterációján.
További információ a lambdakifejezések használatáról: Lambda Expressions in PLINQ and TPL.