何のメリットインスタンスレベルのスレッドローカルな記憶領域?
-
18-09-2019 - |
質問
この質問 につながっていかもしれない スレッドローカルな記憶領域 高レベルの開発の枠組みのようなJavaます。います。
Javaは ThreadLocal<T>
クラス(およびその他の構築),ました。純て データスロット, とぐ ThreadLocal<T>
クラス。(もの ThreadStaticAttribute
, もし、その一例となっているスレッドローカルな記憶領域のために会員データです。) 他のほとんどの現代の開発環境については、機構ので、どちらの言語またはフレームワークです。
どのような問題に直面はスレッドローカルな記憶領域の解決は、すべてのメーなスレッドローカルな記憶領域を超え、標準のオブジェクト指向ディオムを別のオブジェクトインスタンスを含むスレッド-地データはもらえますか?つまり、どのようにこの:
// Thread local storage approach - start 200 threads using the same object
// Each thread creates a copy of any thread-local data
ThreadLocalInstance instance = new ThreadLocalInstance();
for(int i=0; i < 200; i++) {
ThreadStart threadStart = new ThreadStart(instance.DoSomething);
new Thread(threadStart).Start();
}
優れた。
// Normal oo approach, create 200 objects, start a new thread on each
for(int i=0; i < 200; i++) {
StandardInstance standardInstance = new StandardInstance();
ThreadStart threadStart = new ThreadStart(standardInstance.DoSomething);
new Thread(threadStart).Start();
}
できることを単一のオブジェクトをスレッドローカルな記憶領域が多少メモリ効率を必要と少ないプロセッサの資源の減少により、割当て(構造).については、その利点?
解決
どのような問題がスレッドローカルストレージは解決しない、またはどのような利点スレッドローカルストレージは、スレッドローカルデータを格納する別のオブジェクトインスタンスを作成するための標準的なオブジェクト指向のイディオムを介して提供していますか?
スレッドローカルストレージを使用すると、非スレッドセーフなクラスで動作するようにしようとしたとき、または共有状態が原因で発生する可能性があります同期の要件を避けるためにしようとしたときに非常に貴重であるクラスの一意のインスタンスで実行中の各スレッドを提供することができます。
あなたの例対利点について - あなたは、単一のスレッドを生成している場合は、インスタンスを渡し上でスレッドローカルストレージを使用するほとんど、あるいはまったく利点があります。スレッドプールと(直接的または間接的に)作業時ThreadLocal<T>
と同様の構築物は、しかし、非常に貴重になる。
たとえば、私は、私は最近に取り組んで特定のプロセスを持っています。実行される計算の特定の部分をキャッシュすることができ、キャッシュが特定の一致が含まれている場合は、1つの要素を処理するとき、我々は、かなりの時間を削り取ることができます。ただし、キャッシュされた情報は、高いメモリ要件を持っていたので、私たちは最後の処理ステップよりも多くをキャッシュしたくありませんでした。
ただし、スレッド間でこのキャッシュを共有しようとすることは問題です。そのために、我々はそれへのアクセスを同期、そしてまた、彼らはスレッドセーフにするために私たちのクラスの内部にいくつかの余分なチェックを追加する必要があると思います。
代わりにこれを行うための、私は、各スレッドがThreadLocal<T>
で、独自のプライベートキャッシュを維持できるようにするためのアルゴリズムを書き直しました。これは、各スレッドは、独自のプライベートキャッシュを維持することができます。 TPLが使用する分割スキームが一緒に要素のブロックを維持する傾向があるので、各スレッドのローカルキャッシュは、それが必要とされる適切な値を含む傾向があった。
これは、同期の問題を解消するだけでなく、私たちは私たちの場所にキャッシュを維持することができました。総合的な利点は、このような状況では、かなり大きかった。
より具体的な例については、私は<のhref = "http://reedcopsey.com/2010/01/22/parallelism-in-net-part-4-imperative-に書いたこのブログの記事を見てみましょうTPL を使用して、データ並列集約/」REL = 『noreferrer』>集合。あなたはのForEachオーバーロードを使用したときに内部的には、パラレルクラスがThreadLocal<TLocal>
を使用していますそれは(あまりにも、とParallel.For<TLocal>
法)ローカル状態を保持します。これは、ローカル状態はロックを回避するために、スレッドごとに分離して保持される方法です。
他のヒント
ただ、時折、それはスレッドローカルな状態を持っていると便利です。一例は、ログコンテキストのためである - 。あなたはその要求に関係するすべてのログを照合できるように、あなたが現在サービスを提供している要求のコンテキスト、または類似した何かを設定すると便利です。
もう一つの良い例は、.NETのSystem.Random
です。それはあなたが新しいインスタンスにあなたがRandom
を使用するたびに作成するべきではありませんかなり一般的な知識ですので、一部の人々は、単一のインスタンスを作成して、静的変数に入れて...しかしRandom
はスレッドセーフではありませんので、それは厄介です。代わりに、あなたが本当に適切に播種、スレッドごとに1つのインスタンスをしたいです。 ThreadLocal<T>
は、このために素晴らしい作品ます。
同様の例は、スレッド、またはセキュリティコンテキストに関連付けられた培養物である。
一般的に、それはすべての場所でラウンドすぎコンテキストを渡したくない場合です。しかし、それはあなたのAPIの清潔さの邪魔になり - - とあなたが今までに呼び出す必要があった場合にはチェーンが壊れてしまうあなたは、のすべての単一のメソッド呼び出しを作ることができる「RandomContext」または「LOGCONTEXT」を含む<全角>仮想メソッドまたは類似した何かによってあなたにコールバックします別のAPIます。
私の見解では、スレッドローカルデータは、可能な避けるべきものです - しかし、ただ時折、それは本当に便利です。
。 あなたはそれが静的なもので逃げることができます。私が言うことで、の最もの例 - しかし、ただ時折あなたがははインスタンスごと、スレッドごとの情報が必要な場合があります。ここでも、それはそれは便利だ場所を確認するためにあなたの判断を使用して価値がある。
これは、スタックの下に値を渡すことができます。あなたは、コールスタックダウン値を必要とするが、それはメソッドのパラメータとして必要とされる場所にこの値を渡しする方法(または利益)がないときに便利です。 ThreaLocalにおける現在のHttpRequestを格納する上記の例では、この良い例である:別のは、それが必要とされる場所にスタックダウンパラメータとしてのHttpRequestを通過することで
Javaでは、単一の要求は、典型的には、所与のスレッドによって処理され、Webアプリケーションにおいて有用であり得るローカルストレージスレッド。例えば春のセキュリティ、セキュリティフィルターが認証を実行し、スレッドローカル変数にユーザーの資格情報を保存する取ります。
これは、実際の要求処理コードがコードに何かを注入することなく、現在のユーザのリクエスト/認証情報へのアクセスを持つことができます。
あなたは普遍的にいくつかの変数にアクセスして、一連の呼び出しを作りたいです。あなたはすべての呼び出しに引数として渡すことがあります。
function startComputingA(other args) {
global_v = create // declared locally
call A2(other args, global_v)
call A3(other args, global_v)
function A2(other args, global_v) {
call A3(other args, global_v)
function A3(other args, global_v) {
call A4(other args, global_v)
あなたのすべての機能がglobal_v
引数を宣言しなければなりません。これは吸います。あなたはそれが
variable global_v;
function A() { // use global_v and call B() }
function B() { // use global_v and call C() }
しかし、別のスレッドが、これらの機能の当面のいくつかの実行を開始することを起こるかもしれません。これは、破損しているグローバル変数になります。だから、あなたは変数はすべてのルーチンについて、まだ、ないスレッド間で世界的に見えるようにしたいです。あなたは、すべてのスレッドがglobal_v
の別のコピーを持っていると思います。ローカルストレージが不可欠であるとき、ここにあります!あなたは、スレッドローカル変数として宣言しglobal_v
。だから、どのスレッドがどこからでもglobal_v
にアクセスし、それの異なるコピーすることができます。