.NET で同時スレッド間でデータを受け渡す最良の方法は何ですか?
-
01-07-2019 - |
質問
2 つのスレッドがあり、1 つは更新を探すために多数の個別の静的リソースをポーリングする必要があります。もう 1 つはデータを取得してデータベースに保存する必要があります。スレッド 1 はスレッド 2 に処理すべきものがあることをどのようにして伝えることができるでしょうか?
解決
データの部分が独立している場合は、データの部分をスレッドのプールによって処理される作業項目として扱います。スレッドプールを使用し、 QueueUserWorkItem
データをスレッドに投稿します。対称スレッドのプールを使用し、プロデューサとコンシューマの間で発生する必要がある同期の量を制限すると、スケーラビリティが向上します。
たとえば(から MSDN):
TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);
// Queue the task and data.
if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti)) {
Console.WriteLine("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the ThreadPool task has a chance to run. ThreadPool uses
// background threads, which do not keep the application
// running. (This is a simple example of a race condition.)
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
else {
Console.WriteLine("Unable to queue ThreadPool request.");
}
// The thread procedure performs the independent task, in this case
// formatting and printing a very simple report.
//
static void ThreadProc(Object stateInfo) {
TaskInfo ti = (TaskInfo) stateInfo;
Console.WriteLine(ti.Boilerplate, ti.Value);
}
他のヒント
作業項目のキューで Monitor.Wait / Pulse を使用します。
「DB に保存」スレッドは常に実行する必要がありますか?おそらく(可能であれば)最良の選択肢は、保存を行うためにポーリング スレッドに別のスレッドを起動させることだと思われます。ただし、作成されるスレッドの数によっては、最初のポーリング スレッドで ThreadPool.QueueUserWorkItem() を使用する方が効率的な場合もあります。
効率を高めるために、データベースに保存するときに、同期メソッドではなく DB 上で非同期 I/O を使用します。
2 つのスレッド間で直接通信する必要がないようにできる場合は、いつでもそうすべきです。いくつかの同期プリミティブをまとめなければならないため、コードのデバッグはそれほど簡単ではなくなり、「100 万回に 1 回の実行」タイプのバグ (見つけたり修正したりするのは決して楽しいものではありません) を引き起こす非常に微妙な競合状態が発生する可能性があります。
2 番目のスレッドを常に実行する必要がある場合は、その理由と詳細情報をお知らせください。より詳細な回答が得られます。
幸運を!
私は個人的には、スレッド 1 にスレッド 2 が応答できるイベントを発生させると思います。両方のスレッドを開始する制御プロセスによって、スレッドを適切なイベントに結び付けることができます。