.NET の ThreadPool は MinThreads を超える分のスレッドを「1 秒 / 1 スレッド」のペースでしか足さない (= スレッド成長の throttling)。
バーストや sync-over-async があると一時的にキューに溜まり、レスポンスが急激に悪化する。
ここでは 枯渇を意図的に起こし、ThreadPool.SetMinThreads() で改善できることを 1 画面で確認する。
SetMinThreads はこの w3wp ワーカープロセス全体に影響します。検証後は「リセット」を押すか、App Service を再起動してください。
SetMinThreads を呼んだプロセス」と「④ のバーストが実行されたプロセス」が違うことがあります (応答 JSON の processId/machineName で確認可能)。
④ の「枯渇テスト」「改善テスト」ボタンは、サーバ側で 1 リクエスト内で SetMinThreads → 即 burst を実行するので、この問題を回避できます。
processorCount, minThreads, processId, machineName をメモ
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(() => Thread.Sleep(ms)) を count 個並列起動し、Task.WhenAll で全完了を待ちます。
ASP.NET の request thread は 1 本しか使わないので「サーバ内アプリコードでの ThreadPool 飢餓」を測る用途に向いています。
枯渇 / 改善ボタンは 1 リクエスト内で SetMinThreads → 即 burst を実行するため、マルチインスタンスでも確実に動きます。
⚠️ 一度 ThreadPool が大きく成長すると、その後の「枯渇テスト」では既存スレッドが流用されて starvation が見えづらくなります。再現には App Service の再起動が確実です。