C#のスレッドプールを理解する

スレッドは、プロセス内の実行の最小単位です。スレッドプールは、いくつかのスレッド、または正確にはスレッドのコレクションで構成され、バックグラウンドでいくつかのアクティビティを実行するために使用できます。

なぜスレッドプールを使用する必要があるのですか?

スレッドは、初期化、コンテキストの切り替え、およびスレッドが占有するリソースの解放のためにシステム内の多くのリソースを消費するため、コストがかかります。通常、スレッドがI / O操作(ファイル処理、データベース操作、またはネットワークリソースへのアクセスなど)を実行している場合、スレッドはI / O操作が完了するまでオペレーティングシステムによってブロックされます。スレッドは、I / O操作が完了した後、CPU操作を再開します。

スレッドプールは、特定の時点で実行されているスレッドの数を制限し、アプリケーションでスレッドを作成および破棄するオーバーヘッドを回避したい場合に適しています。また、アプリケーションに並行してまたは同時に実行する必要のある多くのタスクがあり、コンテキストスイッチを回避してアプリケーションの応答性を向上させたい場合にも適しています。スレッドプールを作成するには、System.Threading.ThreadPoolクラスを利用できます。

次のコードスニペットは、スレッドプール内のスレッドの最小数を設定する方法を示しています。

ThreadPool.SetMinThreads (50, 50);

ただし、長時間実行されるタスクが実行されている場合、スレッドプールスレッドが長時間ブロックされる可能性があることに注意してください。さらに悪いことに、スレッドプールからのスレッドに依存する着信要求は保留されているか、主にスレッドプールに着信要求を処理するために使用可能なスレッドがないために拒否される場合があります。優先順位が異なるスレッドがある場合や、スレッドを途中で中止する必要がある場合も、スレッドプールは適切な選択ではありません。スレッドの早期終了は、ターンアラウンドタイムが終了する前にスレッドが強制的に停止されたことを意味します。

スレッドプールはどのように機能しますか?

本質的に、スレッドプールを操作するときは、通常、スレッドのコレクションを作成し、アプリケーションでスレッドを使用する前にスレッドプールに格納します。スレッドが必要な場合は、アプリケーションがスレッドを使用する必要があるたびに新しいスレッドを作成するのではなく、それらのスレッドを再利用することになります。

そのため、アプリケーションはスレッドプールにリクエストを送信してスレッドを取得し、スレッドを使用してアクティビティを実行し、完了したらスレッドをスレッドプールに戻します。スレッドプールは、アプリケーションでスレッドを作成できるよりも多くのタスクを実行する場合(プロセスごとに作成できるスレッドの最大数に制限があります)に役立ちます。

スレッドプールを最適化するにはどうすればよいですか?

プロセスが開始されると、CLRによってスレッドのプールが割り当てられます。必要に応じて、スレッドプールのサイズを構成できることに注意してください。ランタイムはスレッドプールをインテリジェントに管理します。スレッドプールが開始されると、スレッドプールにはスレッドが1つだけあります。それ以降、スレッドプールマネージャー(スレッドプールの管理を担当するコンポーネント)は、アプリケーションの負荷が増加するにつれて、より多くのスレッドを作成し、それらをスレッドプールに格納します。つまり、アプリケーションが同時に実行するタスクを増やす必要があります。

任意の時点でスレッドプールで使用できるスレッドの数は、スレッドプール内のスレッドの最大許容制限によって決まります。つまり、スレッドプールで使用可能なスレッドの数は、アプリケーションによるスレッドの消費量に応じて時々変化します。最大制限(スレッドプール内のスレッドの最大数)に達するとすぐに、アプリケーションは新しいスレッドを作成する頻度がはるかに低くなります。

必要に応じて、スレッドプール内の許容スレッドの上限をいつでも自分で設定できます。これを行うには、ThreadPool.SetMaxThreadsプロパティを利用する必要があります。スレッドプール内のスレッドの下限を設定するには、ThreadPool.SetMinThreadsプロパティを使用できます。スレッドプール内のスレッド数のデフォルトの下限は、プロセッサごとに1つのスレッドです。