スレッド数取得は「アプリがどれだけ“並行処理のリソース”を使っているか」を数字で知る技術
業務システムでは、 「なんか CPU が高い」「サーバーが重い」「スレッドプールが枯渇しているかも」 といった問題が起きることがあります。
しかし、スレッドが何本動いているのかを数字で見ないまま原因を探すのは危険です。 そこで役に立つのが スレッド数取得 です。
スレッド数を取得できるようにしておくと、
どれくらいスレッドを消費しているか スレッドプールが枯渇していないか 特定の処理でスレッドが急増していないか
といった“並行処理の健康状態”を把握できます。
ここでは、初心者向けに
スレッド数の基本 Process でプロセス全体のスレッド数を取得 ThreadPool でスレッドプールの状態を取得 ログと組み合わせたスレッド数取得ユーティリティ
を、例題付きで分かりやすく解説します。
スレッド数の基本:.NET には「通常スレッド」と「スレッドプール」がある
スレッドの種類をざっくり理解する
C# のアプリでは、主に次の 2 種類のスレッドが動いています。
通常スレッド(Thread クラスで作るもの)
自分で new Thread(...) して作るスレッド。 作れば作るほど OS のリソースを消費するため、乱用は危険。
スレッドプール(ThreadPool)
.NET が管理する“使い回し可能なスレッドのプール”。 Task.Run や async/await の裏側で使われることが多い。 必要に応じて増えるが、増えすぎると枯渇してアプリが重くなる。
スレッド数取得では、この 「プロセス全体のスレッド数」 と 「スレッドプールの状態」 を見るのが基本です。
Process で「プロセス全体のスレッド数」を取得する
タスクマネージャーに出ている数字と同じものを取る
System.Diagnostics.Process を使うと、 「このアプリが OS 上で何本のスレッドを持っているか」を取得できます。
using System.Diagnostics;
public static void ShowThreadCount()
{
using var process = Process.GetCurrentProcess();
int threadCount = process.Threads.Count;
Console.WriteLine($"現在のスレッド数: {threadCount}");
}
C#例えば、Web サーバーやバッチ処理では、 負荷が高いとスレッド数が 100 を超えることもあります。
ここでの重要ポイントは、 「スレッド数が多い=悪い」ではなく、「急増していると危険」 ということです。
スレッドは OS リソースを消費するため、 増えすぎると CPU 文脈切り替え(コンテキストスイッチ)が増え、逆に遅くなります。
ThreadPool で「スレッドプールの状態」を取得する
「今どれくらい空きがあるか」を知る
スレッドプールは、.NET が自動で管理してくれる便利な仕組みですが、 枯渇すると Task.Run や非同期処理が詰まり始めます。
次のコードで、スレッドプールの状態を取得できます。
using System.Threading;
public static void ShowThreadPoolInfo()
{
ThreadPool.GetAvailableThreads(out int workerThreads, out int ioThreads);
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxIoThreads);
Console.WriteLine($"WorkerThreads: {workerThreads}/{maxWorkerThreads}");
Console.WriteLine($"IOThreads: {ioThreads}/{maxIoThreads}");
}
C#意味は次の通りです。
WorkerThreads
CPU を使う処理用のスレッド。 Task.Run や LINQ の並列処理などで使われる。
IOThreads
I/O 待ち(ネットワーク・ファイルなど)用のスレッド。
例えば、
WorkerThreads: 10/100
なら、「100 本のうち 10 本が空いている(90 本使用中)」という意味です。
ここでの重要ポイントは、 「空きスレッドが少ない=スレッドプールが詰まり始めている」 ということです。
スレッドプールが詰まると、
レスポンスが遅くなる 非同期処理が開始されない タスクが溜まり続ける
といった問題が起きます。
ログと組み合わせたスレッド数取得ユーティリティ
「どの処理でスレッドが増えているか」を後から分析できる
ILogger と組み合わせて、 スレッド数をログに残すユーティリティを作ると便利です。
using System.Diagnostics;
using System.Threading;
using Microsoft.Extensions.Logging;
public static class ThreadLogger
{
public static void LogThreadInfo(ILogger logger, string context)
{
using var process = Process.GetCurrentProcess();
int threadCount = process.Threads.Count;
ThreadPool.GetAvailableThreads(out int workerAvailable, out int ioAvailable);
ThreadPool.GetMaxThreads(out int workerMax, out int ioMax);
logger.LogInformation(
"ThreadInfo Context={Context} Threads={Threads} Worker={WorkerAvailable}/{WorkerMax} IO={IOAvailable}/{IOMax}",
context,
threadCount,
workerAvailable, workerMax,
ioAvailable, ioMax);
}
}
C#使い方の例です。
ThreadLogger.LogThreadInfo(_logger, "ユーザー一覧取得前");
var users = await LoadUsersAsync();
ThreadLogger.LogThreadInfo(_logger, "ユーザー一覧取得後");
C#ログには、例えばこんな行が残ります。
ThreadInfo Context=ユーザー一覧取得前 Threads=45 Worker=80/100 IO=95/100
ThreadInfo Context=ユーザー一覧取得後 Threads=120 Worker=10/100 IO=95/100
ここでの重要ポイントは、 「文脈(どの処理か)とセットでスレッド数を残す」 ことです。
これにより、
「この処理を呼ぶとスレッドが急増している」 「WorkerThreads が枯渇している」
といった問題を特定できます。
実務での使いどころ:スレッドリークやスレッドプール枯渇の検知
スレッド数取得が役立つ典型的な場面
スレッド数取得は、次のような問題の調査に非常に役立ちます。
スレッドリーク(Thread を作りすぎて解放していない)
new Thread を乱用していると、スレッド数が右肩上がりになります。
スレッドプール枯渇
Task.Run の使いすぎ 同期 I/O の多用 ロック競合
などで WorkerThreads が枯渇すると、アプリが極端に遅くなります。
Web サーバーの高負荷時の調査
ASP.NET Core では、スレッドプールの状態がレスポンス速度に直結します。
スレッド数取得ユーティリティを仕込んでおくと、 「どの処理がスレッドを大量に消費しているか」を特定しやすくなります。
まとめ:スレッド数取得は“並行処理の健康診断”のためのユーティリティ
スレッド数取得の本質を一言で言うと、
「アプリがどれくらいスレッドを使っているかを数字で把握し、 スレッドリークやスレッドプール枯渇の兆候を早期に見つける」
ことです。
押さえておきたいポイントは次の通りです。
Process.GetCurrentProcess().Threads.Count でプロセス全体のスレッド数を取得できる。 ThreadPool.GetAvailableThreads でスレッドプールの空き状況を確認できる。 スレッド数は「多い=悪い」ではなく、「急増していると危険」。 ILogger と組み合わせて「文脈付きでログに残す」と、後から分析しやすい。 スレッドリークやスレッドプール枯渇の調査に非常に役立つ。
ここまで理解できていれば、 “なんとなく重い”から一歩進んで、 数字で語れるスレッド診断 ができるようになります。

