.NETの汎用ThreadPool
-
11-07-2019 - |
質問
これは私にとって比較的一般的なタスクです。多くの.NETプログラマーにとっては、
.NET ThreadPoolを使用して、特定の種類のタスクを処理する必要があるワーカースレッドをスケジュールします。
復習として、ThreadPoolのキューイングメソッドとその関連デリゲートのシグネチャは次のとおりです。
public static bool QueueUserWorkItem (
WaitCallback callBack,
Object state
)
public delegate void WaitCallback (Object state)
したがって、一般的な汎用ワーカースレッドクラスは次のようになります。
public class Worker<T> {
public void schedule(T i_task) {
ThreadPool.QueueUserWorkItem(execute, i_task)
}
private void execute(Object o){
T task = (T)o; //What happened to the type safety?
executeTask(task);
}
private void executeTask(T i_task){
//process i_task
}
}
state
パラメーターのタイプに注意してください。 Object
!
.NETチームが QueueUserWorkItem
メソッド(または ThreadPool
クラス全体)をジェネリックにしないことを選んだ理由は何ですか?私は彼らがそれを見落としたとは信じられません。
これが私が見たい方法です:
//in the ThreadPool class:
public static bool QueueUserWorkItem<T> (
WaitCallback<T> callBack,
T state
)
public delegate void WaitCallback<T> (T state)
これにより、ワーカークラスの型が安全になります(より明確になりました、私見):
public class Worker<T> {
public void schedule(T i_task) {
ThreadPool.QueueUserWorkItem<T>(execute, i_task)
}
private void execute(T i_task){
//process i_task
}
}
何か不足しているはずです。
解決
作業キューについて話しているようですね。 (そして、私はクリップのように聞こえます...)
レコードでは、通常、スレッドプールスレッドを短い作業に使用する必要があります。理想的には、長期間有効なキュー用に独自のスレッドを作成する必要があります。 .NET 4.0はCCR / TPLライブラリを採用している可能性があるため、一部の組み込み作業キューは無料で取得できますが、スレッド化された作業キューを作成するのは難しくありません。また、汎用にすることもできます;-p
再質問-状態をスレッドに渡すためのキャプチャされた変数アプローチが好きです( Thread
、 ThreadPool
、または Control.Invoke
):
Thread t = new Thread(() => SomeMethod(arg));
t.IsBackground = true;
t.Name = "Worker n";
t.Start();
これにより、 ThreadPool
を飽和させることなく、スレッドをよりきめ細かく制御できます。
他のヒント
匿名のデリゲートまたはラムダをスレッドプールに(変数のキャプチャを介して)渡すことで、好きな状態をパッケージ化するのは簡単なので、汎用バージョンは必要ありません。
たとえば、ユーティリティ関数を書くことができます:
static void QueueItem<T>(Action<T> action, T state)
{
ThreadPool.QueueUserWorkItem(delegate { action(state); });
}
しかし、プールされたタスクの状態が必要なときはいつでも自分でデリゲートを使用することができるため、それほど便利ではありません。
ThreadPoolは、ジェネリックを持たない.NET 1.1以降に存在します。
下位互換性を損なわないように選択した方法が気に入っています:-)