How to: Write a Parallel.For Loop That Has Thread-Local Variables
[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]
This example shows how to use thread-local variables to store and retrieve state in each separate task that is created by a For loop.
By using thread-local data, you can avoid the overhead of synchronizing a large number of accesses to shared state.
Instead of writing to a shared resource on each iteration, you compute and store the value until all iterations for the task are complete.
You can then write the final result once to the shared resource, or pass it to another method.

Example
Namespace ThreadLocal
Class Test
PrivateSharedSub Main()
Dim nums AsInteger() = Enumerable.Range(0, 1000000).ToArray()
Dim total AsLong = 0
' Use type parameter to make subtotal a long, not an int
Parallel.For(OfLong)(0, nums.Length, Function() 0, Function(j, [loop], subtotal)
subtotal += nums(j)
Return subtotal
EndFunction, Function(x) Interlocked.Add(total, x))
Console.WriteLine("The total is {0}", total)
Console.WriteLine("Press any key to exit")
Console.ReadKey()
EndSubEndClassEndNamespace
namespace ThreadLocal
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
class Test
{
staticvoid Main()
{
int[] nums = Enumerable.Range(0, 1000000).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;
},
(x) => Interlocked.Add(ref total, x)
);
Console.WriteLine("The total is {0}", total);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
The first two parameters of every For method specify the beginning and ending iteration values.
In this overload of the method, the third parameter is where you initialize your local state. "
Local state" in this context means a variable whose lifetime extends from just prior to the first iteration of the loop on the current thread, to just after the last iteration.
The type of the third parameter is a Func`Func<(Of <(TResult>)>) where TResult is the type of the variable that will store the thread-local state.
Note that in this example, a generic version of the method is used, and type parameter is long.
The type parameter tells the compiler the type of the temporary variable that will be used to store the thread-local state.
The () => 0 ( Function() 0 ) expression in this example means that the thread-local variable is initialized to zero.
If the type parameter is a reference type or user-defined value type, then this Func would look like this:
//C#
() => new MyClass()
' Visual Basic
Function() new MyClass()
The fourth type parameter is where you define the loop logic.
Intellisense shows that it has a type of Func<int, ParallelLoopState, long> or Func(Of Integer, ParallelLoopState, Long).
The lambda expression expects three input parameters in that same order corresponding to those types.
The last type parameter is the return type.
In this case the type is long because that is the type we specified in the parallel.For type parameter.
We call that variable subtotal in the lambda expression, and return it.
The return value is used to initialize subtotal on each subsequent iteration.
You can also think of this last parameter simply as a value that is passed to each iteration, and then to the localFinally delegate when the last iteration is complete.
The fourth parameter is where you define the method that will be called once, after all the iterations on this thread have completed.
The type of the input parameter again corresponds to the type parameter of the For method and the type returned by the body lambda expression.
In this example, the value is added to a variable at class scope in a thread safe way.
By using a thread-local variable, we have avoided writing to this class variable on every iteration of every thread.
For more information about how to use lambda expressions, see Delegates and Lambda Expressions in PLINQ and the Task Parallel Library.

See Also
|
.NET Framework 4 方法 : スレッド ローカル変数が Parallel.For ループを記述します。
[このドキュメントはプレビュー版であり、後のリリースで変更されることがあります。 空白のトピックは、プレースホルダーとして挿入されています。]
スレッド ローカル変数を使用して保存してから各 For ループによって作成される個別のタスクの状態を取得するには次の使用例に示します。
スレッド ローカル データを使用して、多数の共有状態へのアクセスを同期化のオーバーヘッド回避できます。
各繰り返しで、共有リソースへの書き込み] の代わりに計算してタスクのすべてのイテレーションが完了するまで値を格納します。
共有リソースへの 1 回だけなの最終的な結果の書き込みまたは別のメソッドに引き渡してできます。

使用例
Namespace ThreadLocal
Class Test
PrivateSharedSub Main()
Dim nums AsInteger() = Enumerable.Range(0, 1000000).ToArray()
Dim total AsLong = 0
' Use type parameter to make subtotal a long, not an int
Parallel.For(OfLong)(0, nums.Length, Function() 0, Function(j, [loop], subtotal)
subtotal += nums(j)
Return subtotal
EndFunction, Function(x) Interlocked.Add(total, x))
Console.WriteLine("The total is {0}", total)
Console.WriteLine("Press any key to exit")
Console.ReadKey()
EndSubEndClassEndNamespace
namespace ThreadLocal
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
class Test
{
staticvoid Main()
{
int[] nums = Enumerable.Range(0, 1000000).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;
},
(x) => Interlocked.Add(ref total, x)
);
Console.WriteLine("The total is {0}", total);
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
For
メソッドのそれぞれの最初の 2 つパラメーターは、開始と終了のイテレーションの値を指定します。
このオーバーロード メソッドのでは、[第 3 パラメーターが、ローカルの状態を初期化します。"
ローカルの状態"このコンテキストでは、変数の有効期間は、最後のイテレーション後だけに現在のスレッドで、ループの最初の反復処理の直前にから拡張を意味します。
3 番目のパラメーターの型は Func です ` Func<(Of <(TResult>)>) TResult スレッド ローカル状態を格納する変数の型が入ります。
この例で、メソッドのジェネリック バージョンが使用され型パラメーターは の長い。
型パラメーターはスレッド ローカル状態を格納する使用される一時変数の型に、コンパイラに指示します。
() => 0 ( Function() 0 ) 式この例では、スレッド ローカル変数 0 に初期化されていることを意味します。
型パラメーターは、参照型またはユーザー定義の値の型が場合、しこの Func よいます。
//C#
() => new MyClass()
' Visual Basic
Function() new MyClass()
4 番目の種類パラメーターがループ ロジックを定義する場所です。
Intellisense、Func<int, ParallelLoopState, long>Func(Of Integer, ParallelLoopState, Long) の型が設定されていることを示しています。
ラムダ式はこれらの型に対応する同じ順序で 3 つの入力パラメーターを受け取る。
最後の型パラメーターが戻り値の型です。
ここでお parallel.For 型パラメーターで指定された型はため、型は長です。
、ラムダ式でその変数 subtotal を呼び出すし、それを返します。
戻り値は、以降各イテレーションでの小計を初期化する使用します。
またこの最後のパラメーターの最後のイテレーションが完了したときに、毎回、次に、localFinally デリゲートに渡される値としてだけと考えることができます。
第 4 パラメーターが呼び出される、このスレッドでのすべてのイテレーションが完了したらメソッドを定義する場所です。
入力パラメーターの型をもう一度、For メソッドと、本文のラムダ式によって返される型の型パラメーターに対応しています。
この例で、値がスレッドでクラス スコープで変数に追加されます安全な方法です。
スレッド ローカル変数を使用すると、私たち各イテレーションのすべてのスレッド上でこのクラスの変数への書き込みを回避しました。
ラムダ式を使用する方法については、デリゲートと PLINQ と、タスクの並列ライブラリ内のラムダ式 を参照してください。

参照
|