5

私の質問はリアルタイム処理に関するものではないかもしれませんが、そうかもしれません。

私のアプリケーションには、GUI よりもはるかに重要なスレッドがいくつかありますが、少なくとも GUI を使用できるようにしたいと考えています。常にロックしたくありません。実行中の処理の結果を考慮して、画面を更新したいと考えています。

現在、重要なアイテムはすべて別のスレッドに分離されており、GUI にデリゲートを呼び出して結果を表示しています。

私の GUI は動作しますが、タブを変更したり、最小化/最大化したりすると、他のスレッドが 0.1 秒の制限時間内に操作を実行できなくなるまで妨害されることが知られています。

これは、デリゲートを呼び出すために行っていることです。

delegate void FuncDelegate(ResultContainer Result);
FuncDelegate DelegatedDisplay= new FuncDelegate(DisplayResults);
//then later on
Invoke(DelegatedDisplay, Result);

私の重要なプロセスのほとんどは、さまざまなバッファー (ArrayLists および通常のリスト) からプルおよびプッシュして、連続ループで実行されるスレッドです。

私の重要なスレッドの 1 つは、次を使用して毎回起動されます。

Thread mythread = new Thread(new ThreadStart(ProcessResults));
mythread.Start();

スレッドをループで実行してリストからプルするのではなく、これを行うことを考えた理由は、クロック時間が不足している理由は、ポーリングループが多すぎると心配しているからだと思ったからです。リソース(ただし、ポーリングがマイナスになるたびに Thread.Sleep(5) を使用しています)。

並行プロセスが必要になるたびに新しいスレッドを起動すると、貴重な時間が費やされますか? これはループであるべきですか?私のループのせいですか?

スレッドに他のスレッドよりも高い優先度を与えることはできますか? それとも、Thread.Sleep を使用するしかありませんか? より高いスレッド優先度を割り当てた場合、他のスレッドが存続できることをどのように確認できますか?

単純なフォーム イベントが他のスレッドの妨げになっているのはなぜですか? GUI スレッドに割り当てるリソースの量を減らす方法はありますか? 他のスレッドが時間切れになった場合、Thread.Sleep を使用して Form イベントをブロックできますか?

私のすべてのイライラする質問への回答が足りないのですが、私の混乱を理解するために使用できるスレッドプロファイラーのようなものはありますか? 「Managed Stack Explorer」を使用してみましたが、どういうわけか、アプリケーションにあるスレッドが常に表示されるわけではありません。

この問題に関する助けがあれば、私は大いに役立ちます。

4

2 に答える 2

5

さて、ここから始めます:

Invoke(DelegatedDisplay, Result);

これは、UI スレッドが実際に描画操作を実行するまでバックグラウンド スレッドを待機させてから続行することを意味します。スレッドの観点からは、それは永遠です。UI への非同期更新を調査することをお勧めします。

BeginInvoke(DelegatedDisplay, Result);

これは、UI スレッドに「機会があれば、この描画アクションを実行してください」と伝えてから、実行していた作業を続行することと同じです。

ただし、これにより、を使用した場合には発生しなかったスレッドセーフの問題が発生する可能性があることに注意してくださいInvoke。たとえばResult、UI が描画しようとしているときにバックグラウンド スレッドがまだ変更されている場合、予期しない競合状態が発生する可能性があります。

Control.InvokeControl.BeginInvokeを参照してください。

于 2012-05-31T13:43:44.230 に答える
1

のようなマーシャリング手法を使用してUIInvokeBeginInvoke更新することは、問題の一部です。実際、UIとワーカースレッドの相互作用にマーシャリング操作を使用することはめったにありません。これは、それほど優れたソリューションではないためです。まあ、率直に言って、それはこの性質のほとんどの場合に最悪の解決策になる可能性があります(そして通常はそうです)。

私が通常行うことは、ワーカースレッドに結果または進行状況を共有データ構造に公開させ、UIスレッドに、目前の状況に最適に機能するように調整された間隔でSystem.Windows.Forms.Timer(または)を使用してポーリングさせることです。DispatcherTimer

これがどのように見えるかです。

public class YourForm : Form
{
  private ConcurrentQueue<ResultContainer> results = new ConcurrentQueue<ResultContainer>();

  public UpdateTimer_Tick(object sender, EventArgs args)
  {
    // Limit the number of results to be processed on each cycle so that
    // UI does not stall for too long.
    int maximumResultsToProcessInThisBatch = 100;

    ResultContainer result;
    for (int i = 0; i < maximumResultsToProcessInThisBatch; i++)
    {
      if (!results.TryDequeue(out result)) break;
      UpdateUiControlsHere(result);
    }
  }

  private void WorkerThread()
  {
    while (true)
    {
      // Do work here.
      var result = new ResultContainer();
      result.Item1 = /* whatever */;
      result.Item2 = /* whatever */;
      // Now publish the result.
      results.Enqueue(result);
    }
  }
}

重要なのは、人々はUIを自動的に使用InvokeまたはBeginInvoke更新するようにプログラムされているため、より良いソリューションを無視することです。これらのマーシャリング技術がカーゴカルトプログラミングの領域に適合するようになりました。私はいつもこのトピックをリッピングしているので、おそらくこのトピックに関しては壊れたレコードのように聞こえます。上で使用した手法には、次の利点があります。

  • これにより、マーシャリング操作によって課されるUIスレッドとワーカースレッド間の緊密な結合が解除されます。
  • ワーカースレッドは、の場合のようにUIスレッドからの応答を待つ必要はありませんInvoke
  • の場合のように、UIメッセージキューが飽和する可能性はありませんBeginInvoke
  • UIスレッドとワーカースレッドの両方でスループットが向上します。
  • UIスレッドは、UIスレッドを更新するタイミングと頻度を指示します。
  • Invokeコードを(文字通り)またはBeginInvoke呼び出しで散らかす必要はありません。
  • マーシャリング操作は費用がかかります。
  • コードは最終的にはよりエレガントに見えます。

並行プロセスが必要になるたびに新しいスレッドを起動すると、貴重な時間がかかりますか?これはループである必要がありますか?私のループのせいですか?

私はスレッドを意地悪に作成することを避けます。スレッドをループで実行し続けることができれば、それはより良いでしょう。

スレッドに他のスレッドよりも高い優先度を与えることはできますか、それともThread.Sleepを使用することが唯一の選択肢ですか?より高いスレッド優先度を割り当てた場合、他のスレッドが存続できることをどのように確認できますか?

この場合、ワーカースレッドに高い優先度を与えるとおそらく役立つでしょう。Thread.Sleep(5)ただし、5msはスリープしません。それはそのようには機能しません。ちなみに、に渡すことができるいくつかの特別な値がありますThread.Sleep

  • Thread.Sleep(0)は、任意のプロセッサで同じかそれ以上の優先度を持つ任意のスレッドに譲ります。
  • Thread.Sleep(1)は、任意のプロセッサ上の任意のスレッドに譲ります。

単純なフォームイベントが他のスレッドをそれほど妨げているのはなぜですか?GUIスレッドに割り当てられたより少ない量のリソースを与える方法はありますか?他のスレッドの時間が不足している場合、Thread.Sleepを使用してFormイベントをブロックできますか?

を使用しているためですInvoke。マーシャリング操作を回避すると、スレッドが切り離されるため、非常に役立ちます。Thread.SleepUIスレッドでは使用しないでください。UIスレッドが正しく機能するには、ブロックを解除したままにする必要があります。上記で提案したソリューションを使用する場合は、UIスレッドを調整する方がはるかに簡単です。

于 2012-05-31T15:46:14.390 に答える