1

時々かなり遅く実行されるプログラムがあります。

Teleriks Justtraceを試して、アプリケーションのハングを引き起こす可能性のあるものを見つけました。

非UIスレッド(したがって、実際にはハングの原因ではないと思います)は非同期になります。オブジェクトを取得し(作業項目をエンキューし)、いくつかの作業を行うためにオブジェクトをデキューします。

エンキュー:

public void EnqueueObject(WorkUnit workunit)
        {
            try
            {
                workUnits.Add(workunit);
            }
            catch (Exception ex)
            {
                /handle exception
            }
        }

デキュー:

public WorkUnit Dequeue()
        {
            try
            {
                WorkUnit aWorkUnit  = null;
                workUnits.TryTake(out aWorkUnit, 1000);

                return aWorkUnit ;
            }
            catch (InvalidOperationException ex)
            {
                // 

            }
                    return null;
        }

TryTakeは、現在の作業の中止をチェックするために使用されました(呼び出されたときにエラーをスローするBlockingCollection Completeメソッドの代わりに-プログラムフローにエラーを使用したくない)

デキューするための呼び出し:

 while(!isStopped)
 {
   ProcessWorkItem(Dequeue());
 }

ここまではとてもシンプルに見えます。

問題は、Teleriks JustTraceが示すように、「workUnits.TryTake(out aWorkUnit、1000);」という行であるということです。プログラムの総実行時間の30%を要します。

どうすればいいの?

詳細を見ると、TryTake System.Threading.Monitor.Wait内で常に時間がかかることがわかります。待機するとスレッドがスリープ状態になると思ったので、待機中に何かを消費することはありません。思考の誤りはどこにありますか?

4

1 に答える 1

0

workUnits.TryTake(out aWorkUnit)タイムアウト パラメータなしで使用してみることができます。次に、whileループを次のように変更する必要があります。

 while(!isStopped)
 {
    WorkUnit wu = Dequeue(); 
    if(wu != null) 
       ProcessWorkItem(wu);
    else
       Thread.Sleep(40);
 }

また、このコードを UI スレッドで実行すると、UI が応答しなくなります。たとえばBackgroundWorker、操作に使用する必要があります。BackgroundWorkerMSDN ドキュメントのクラスの説明は次のとおりです。

BackgroundWorker クラスを使用すると、別の専用スレッドで操作を実行できます。ダウンロードやデータベース トランザクションなどの時間のかかる操作により、実行中にユーザー インターフェイス (UI) が応答を停止したように見える場合があります。レスポンシブな UI が必要で、そのような操作に関連する長い遅延に直面している場合、BackgroundWorker クラスは便利なソリューションを提供します。

于 2013-02-27T13:03:16.973 に答える