🧵 ThreadPool 枯渇 / MinThreads チューニング — 動確

このページでできること

.NET の ThreadPool は MinThreads を超える分のスレッドを「1 秒 / 1 スレッド」のペースでしか足さない (= スレッド成長の throttling)。 バーストや sync-over-async があると一時的にキューに溜まり、レスポンスが急激に悪化する。 ここでは 枯渇を意図的に起こし、ThreadPool.SetMinThreads() で改善できることを 1 画面で確認する。

⚠️ プロセス全体に効きます。 SetMinThreads はこの w3wp ワーカープロセス全体に影響します。検証後は「リセット」を押すか、App Service を再起動してください。
💡 マルチインスタンス / 複数 w3wp の罠
App Service が複数 VM (Auto Scale) や Web Garden を使っていると、HTTP リクエストが 毎回別プロセス にロードバランスされ、 「② の SetMinThreads を呼んだプロセス」と「④ のバーストが実行されたプロセス」が違うことがあります (応答 JSON の processId/machineName で確認可能)。 ④ の「枯渇テスト」「改善テスト」ボタンは、サーバ側で 1 リクエスト内で SetMinThreads → 即 burst を実行するので、この問題を回避できます。
📋 推奨手順 (1〜5 を順に押すだけ)
  1. 現在状態 を更新 → processorCount, minThreads, processId, machineName をメモ
  2. サーバ内バースト の「枯渇テスト (set 1 → burst)」を実行 → ratio が 2 以上になることを確認
  3. 同じくバーストの「改善テスト (set 256 → burst)」を実行 → ratio が 1 に近づくことを確認
  4. (任意) 並列リクエスト テスト を試す → ARR Affinity の影響でばらつくのも観察
  5. 検証完了後、MinThreads リセット を押して ProcessorCount に戻す

① 現在の ThreadPool 状態

② MinThreads 設定 / リセット

ThreadPool.SetMinThreads(workerThreads, completionPortThreads) を呼びます。 既定 (= ProcessorCount) より大きな値を設定すると、その値までは 1 秒/スレッドの成長制限なく即時にスレッドが確保されます。

③ 並列リクエスト テスト (クライアント発火)

ブラウザから ./api/sync-sleep?ms=N を count 個並列発射します (各リクエストは server 側で Thread.Sleep(ms) で request thread を占有)。 ThreadPool に十分な worker thread が確保できていれば理想時間 (= sleepMs) に近い時間で全部完了します。 MinThreads 不足だと order of seconds 遅くなります。

④ サーバ内バースト テスト (Task.Run)

サーバ側で Task.Run(() => Thread.Sleep(ms)) を count 個並列起動し、Task.WhenAll で全完了を待ちます。 ASP.NET の request thread は 1 本しか使わないので「サーバ内アプリコードでの ThreadPool 飢餓」を測る用途に向いています。 枯渇 / 改善ボタンは 1 リクエスト内で SetMinThreads → 即 burst を実行するため、マルチインスタンスでも確実に動きます。

⚠️ 一度 ThreadPool が大きく成長すると、その後の「枯渇テスト」では既存スレッドが流用されて starvation が見えづらくなります。再現には App Service の再起動が確実です。

その他の機能 (別エリア)