2017-07-11 8 views
2

IISアプリケーションのパフォーマンス/スケーラビリティテストを行っていますが、実際には本番環境でのクロールが遅くなることがあります。私はNUnitを使って一貫して遅さを再現することができます。スレッド飢餓の検出/診断

テスト中、または生産が遅くなった場合、CPUとメモリが急上昇しません。私の強い疑いは、ボトルネックの原因となっているCPU、メモリ、I/O、またはデータベースアクセスではないと思われるため、アプリケーションがスレッドスターベーションに苦しんでいることです。私はの表示が何かの兆候を見てスレッドの飢餓と思われる;例えば、NLogの非同期ログファイルの書き込みは、長い時間の沈黙とそれに続く古いタイムスタンプの活動のバースト(すなわち、優先順位の低いスレッドが書き込みを行うためにスレッドを解放するのを待っている)の傾向があります。

どのような手順私が決定的にアプリケーションが実際に飢えたスレッドであることを判断するために取ると、(それが事実であると仮定して)問題を引き起こしているシステムの正確な領域を特定することができますか?

編集

私はほとんどすべてのコードは、(それがレガシーシステムです)同期であることを言及するのを怠っ。 Sinatrさんのコメントに基づいて

+1

あなたは 'TaskCreationOptions.LongRunningを指定せずに、一度に多くの長時間実行タスクを開始しています'?もしあなたがそうした場合、デフォルトのスケジューラは新しいスレッドを割り当てる前に500ミリ秒のようなものを待っているので、起動するには新しい生存予定の短いタスクは起動時に*巨大な遅延を経験します。 'ThreadPool.SetMinThreads'で修正することができますが、パフォーマンスの低下を防ぐために、長時間実行する方がよいでしょう。 – Sinatr

+0

興味深い。これは同期コードにも当てはまりますか? –

+0

@Sinatr *長期間実行されていないタスクは、スレッドスターベーションがないようにする方法です。 'LongRunning'を使ってたくさんのタスクを作成するのは、スレッドの飢餓をどのように作成するかです。 – Servy

答えて

1

は、私は、より高いデフォルト値にMinThreadsを設定When to use TaskCreationOptions.LongRunning?

への回答を含むThreadPool.SetMinThreadsとTaskCreationOptions.LongRunningにいくつかの読書は、私の場合は大きな違いを作りました。私は、単純なバックグラウンドプロセスを作成して、テスト実行中にThreadPoolのAvailable Threadsが大幅に変化していて、MinThreadsの値を超えていたかどうかを確認しました。

私が診断に使用したコードは次のとおりです。本番用ではありません。ここに示すスレッドの使用状況のレポートは、最初に増加した場合にのみ面白いでしょう。また、タイマーには経過時にスレッドが必要なので、利用可能なスレッドを待つ必要もあります。

静的varsの:起動時に

private static Timer _timer; 
    private static int _lastActiveThreads; 
    private static int _lastAvailableThreads; 
    private static int _maxThreads; 
    private static int _minThreads; 

ラン:

int completionPortThreads; 

    ThreadPool.GetMaxThreads(out _maxThreads, out completionPortThreads); 
    ThreadPool.GetMinThreads(out _minThreads, out completionPortThreads); 

    _timer = new Timer 
    { 
     AutoReset = true, 
     Interval = 500, 
    }; 

    _timer.Elapsed += TimerElasped; 
    _timer.Start(); 

経過方法:

private static void TimerElasped(object sender, ElapsedEventArgs e) 
    { 
     int minWorkerThreads; 
     int availWorkerThreads; 
     int completionPortThreads; 

     ThreadPool.GetMinThreads(out minWorkerThreads, out completionPortThreads); 
     ThreadPool.GetAvailableThreads(out availWorkerThreads, out completionPortThreads); 

     var activeThreads = _maxThreads - availWorkerThreads; 

     if (availWorkerThreads != _lastAvailableThreads) 
     { 
      _lastAvailableThreads = availWorkerThreads; 
      if (activeThreads > _lastActiveThreads) 
      { 
       _lastActiveThreads = activeThreads; 
       Logger.Log($"+++++ Active Threads is now: {activeThreads}"); 

       if (activeThreads > _minThreads) 
       { 
        var diff = activeThreads - _minThreads; 
        Logger.Log($"+++++ Active threads is now {activeThreads}, which is {diff} more than minThread value of {_minThreads}. This may be causing delays."); 
       } 
      } 
     } 
    } 
関連する問題