2017-03-15 15 views
0

私のアプリケーションは多くのスレッドで動作し、各スレッドはAddDetailLog関数を使用してスレッドの進行状況をグローバルなtextBoxに追加するので、各スレッドの進行状況に従うことができます。この機能は1秒間に500回以上呼び出すことができます。私はVS2015プロファイラを使用したとき、私のCPUの50%を使用するのはこの関数だとわかりました。私は150スレッド以上をロードすると、私のCPUは100%であるので、私は本当にこの機能を最適化する必要があります。呼び出しログ機能の最適化 - マルチスレッド

マルチスレッドに最適化する機能:マルチスレッドためのもので

public void AddDetailLog(string text) 
    { 
     if(Program.SHOWDETAILSLOG) 
     { 
      if (this.textBox_log.InvokeRequired) 
      { 
       SetTextCallback d = new SetTextCallback(AddDetailLog); 
       this.Invoke(d, new object[] { text }); 
      } 
      else 
       this.textBox_log.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "] - " + text + Environment.NewLine); 
     } 
    } 

、私はスレッド(ないのBackgroundWorker)の全てが同じてtextBoxに作用しているので、私のテキスト入力欄に入力、呼び出しを必要とするかどうかを確認する必要があります私のグローバルフォームに。

誰かがこの機能を最適化する考えがあれば、私はそれを耳にしてうれしく思います。彼らはGDIのメッセージポンプを通じて同期終わるだろうと

おかげ

+2

メッセージを表示することなく(メッセージを表示せずに)バッファを作成し、1秒ごとに起動してそのテキストを「TextBox」に追加するバッファを作成することもできます。または、自分自身に「__really__ need?これらのログメッセージをすべて表示するには? –

答えて

3

まず第一に、Control.Invoke()ブロック呼び出しプロセスは、最終的にあなたのバックグラウンドスレッドの目的を破って。代わりにBeginInvoke()を使用すると、非同期で呼び出しを行うことができるため、バックグラウンド処理を継続できます。

第二には、そのレートでTextBox制御への書き込みがTextBox.Textへの変更が他のものの間で更新されたテキストでコントロールを再描画しますTextChangedを、起動しますので、あなたを遅くしようとしています。これは500回/秒です。特にテキストボックスを下にスクロールするコードのようなカスタムTextChangedハンドラを使用するとUIスレッドがきれいに焼き付けられます。

代わりに、ロガーにより簡単なメモリ内オブジェクトを書き込んでから、フォームにTimerを実行して、TextBoxコントロールでこれらのメッセージを取得、連結、および表示することをおすすめします。高い並行性を念頭に置いて、ConcurrentQueue<string>をお勧めします。あなたのバックグラウンドワーカーがログエントリをエンキューするために "TryAdd"コールを実行すると、UI Timer.TickハンドラはTryTakeでそれらをデキューし、よりUIに優しい方法でそれらをTextBoxに追加します(10バッチのエントリを連結してからテキストボックス)。

最後に、TextBoxの内容が長いほどレンダリングにかかる​​時間が長くなります。実際に表示する必要がある文字列の部分をスクロールバーを表示するために文字列の表示サイズを計算する必要があるためです。私はあなたのログ表示の "バックエンド"を30K文字程度で切り捨てます。潜在的に貴重な情報を失わないように、同じハンドラはメッセージをStreamWriterに渡してすべてをファイルに書き込むことができます。ここに非同期処理の別のレベルを追加して、UIの応答性を保つことができます。

関連する問題