スレッドとは?
そもそもスレッドって何?という話ですが、wikiから抜粋すると、
コンピュータプログラムにおいて特定の処理を行うための一貫性のある命令の流れ
と説明されています。
アプリ全体のプロセスのうち、スレッドは命令を受けて実際に処理を実行する実行役というイメージです
例えば、アプリ全体をレストランだとすると
プロセス 👉 厨房
スレッド 👉 シェフ
といったところでしょうか。
"料理を提供する"という役割の中に何人シェフがいても問題ありませんね。
むしろ何人かのシェフをうまく利用することで効率よくレストランを回すことができます。
プログラムでも同じ考え方ができます。
画面を描画するUIスレッドがメインで動いていたとして、重いIO処理やDB接続処理は別のスレッドに任せることで画面が固まったりすることなくユーザビリティの高いアプリケーションを作ることができます。
スレッドを作りすぎることによる弊害
ここで、「じゃあ重そうな処理は全部別スレッドを作って任せれば良いのね!」とお考えになった方、ちょっとお待ちください!
スレッドを新しく作るということは、いわば新しいシェフをもう一人雇うということ。
面接 → 作業の説明 → 退勤の手続き → ...
本当はもう一人雇う必要のないタスクに対してもこのような作業を毎回やってしまうことになります。レストランのコスト的にもこれは望ましいことではありませんよね?
これはプログラムでも同じことが言えて、スレッドの作成時OSにはそれなりの負担がかかります。
手動でスレッド管理をしていると、本当はそこまで負荷の高くない処理にまでスレッドが作成されてしまい、パフォーマンスに大きな影響を与える懸念があります。
.NETが用意している賢いスレッド管理を使おう!
そこで活躍するのが.NETで用意されているThreadPoolです!
あらかじめ雇用しておいた超優秀なシェフのチームみたいなイメージです。
このチームに作業をお願いすれば、自動で待機中のシェフに作業を割り当ててくれます。チーム内で作業を上手いこと回してくれるので、自ら新しいシェフを雇う必要はなく、無駄なコストが発生することもありません。
ThreadPoolの使い方
そんな優秀なチームに仕事を依頼するのはたった一行でできます。
ThreadPool.QueueUserWorkItem(/* スレッドプールで実行したいコールバック関数 */);
QueueUserWorkItemメソッドを呼び出すだけですね☝️
実際に別スレッドで実行されていることを確認してみました。
public class Program
{
public static void Main()
{
Console.WriteLine($"Main thread ID: {Thread.CurrentThread.ManagedThreadId}");
ThreadPool.QueueUserWorkItem(Hello);
ThreadPool.QueueUserWorkItem(Hello);
ThreadPool.QueueUserWorkItem(Hello);
ThreadPool.QueueUserWorkItem(Hello);
Console.WriteLine($"メインスレッドからこんにちは! ID:{Environment.CurrentManagedThreadId}");
}
private static void Hello(Object stateInfo)
{
Console.WriteLine($"スレッドプールからこんにちは! ID:{Environment.CurrentManagedThreadId}");
}
}
// 出力結果
// Main thread ID: 1
// メインスレッドからこんにちは! ID:1
// スレッドプールからこんにちは! ID:4
// スレッドプールからこんにちは! ID:6
// スレッドプールからこんにちは! ID:7
// スレッドプールからこんにちは! ID:4
自動でスレッドが分けられていて、手の空いたスレッドは再利用されていることがわかります。
ThreadPoolの特徴
- スレッド数の最適化
要求されている仕事量に応じてスレッド数の増減を自動で管理してくれます。
- バックグランドスレッドを使用
アプリのメインスレッドが終了すればスレッドプールの完了を待たずにアプリが終了可となります。意図せずアプリが閉じられなくなるという心配が無用に!
使用上の注意点
ThreadPoolではスレッド数の最大・最小値を実装で制限することができます。
しかし、公式ドキュメントでは無闇にスレッド数を制限すべきではないと名言されています🫣
ほとんどの場合、スレッドを割り当てるためのスレッド プール独自のアルゴリズムを使用することでスレッド プールのパフォーマンスが向上します。
実装者の判断で制限せずに、優秀なチームに管理は任せましょうということですね!
