4

スレッド内のローカル サーバーから一連の変数を読み取るベンチマーク ツールをプログラミングしています。

            int countReads = 1000;

            Int64 count = 0;

            for (int i = 0; i < countReads; i++)
            {
                Thread.CurrentThread.Priority = ThreadPriority.Highest;
                DateTime start = DateTime.Now;

                session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);

                DateTime stop = DateTime.Now;
                Thread.CurrentThread.Priority = ThreadPriority.Normal;

                TimeSpan delay = (stop - start);

                double s = delay.TotalMilliseconds;
                count += (Int64)s;

                Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
                {
                    progressBar1.Value = i;
                }));
            }

            double avg = (double)count / countReads;

            Dispatcher.Invoke(DispatcherPriority.Input, new Action(() =>
            {
                listBox1.Items.Add(avg);
            }));

読み取りを進めるのにかかったタイムスパンを計算し、最後に平均タイムスパンを取得しています。

            DateTime start = DateTime.Now;

            session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);

            DateTime stop = DateTime.Now

プログレスバーを更新せずにコードを実行すると、平均で約 5 ミリ秒かかりました。しかし、私がそれを実行すると

            Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
            {
                progressBar1.Value = i;
            }));

平均で約 10 ミリ秒かかります。

私の質問は、プログレスバーを使用するとタイムスパンが高くなるのはなぜですか? 読み取りのタイムスパンを計算しているだけです。プログレスバーの更新は含まれません。

読み取りタイムスパンに影響を与えないように、UI ペインティングを退避する方法はありますか?

ご協力いただきありがとうございます。

よろしくお願いします

4

4 に答える 4

11

Invoke進捗情報を UI スレッドに転送するために使用を停止します。進捗情報を共有データ構造または変数に発行し、適切な間隔でタイマーを使用して UI スレッドにポーリングさせます。私たち全員が洗脳されInvokeて、ワーカーと UI スレッドの対話を行うためのすべての方法であると考えるようになっているようですが、単純な進行状況情報については、最悪の方法になる可能性があります (多くの場合そうです)。

UI スレッドでタイマーを使用するポーリング メソッドには、次の利点があります。

  • Invokeこれにより、UI スレッドとワーカー スレッドの両方に課される密結合が解消されます。
  • UI スレッドは、その逆ではなく、いつ、どのくらいの頻度で進捗情報を更新するかを決定します。立ち止まって考えてみると、とにかくこうあるべきです。
  • UI スレッドとワーカー スレッドの両方でスループットが向上します。

session.Readこれは、なぜ実行が遅くなるように見えるのかについてのあなたの質問に直接答えないことを知っています. 進捗情報を更新するための戦略をプッシュ モデル (経由Invoke) からプル モデル (タイマー経由) に変更してみてください。それが違いを生むかどうかを確認してください。そうでない場合でも、上記の理由により、プル モデルに固執します。

于 2012-04-18T15:03:18.163 に答える
2

MSDNがDispatcher.Invokeについて述べていることは次のとおりです

Dispatcher が関連付けられているスレッドで、指定されたデリゲートを同期的に実行します。

したがって、基本的にはDispatcher.Invoke、ディスパッチャ スレッドがリクエストを処理するまでブロックします。

Dispatcher.BeginInvoke代わりに試してください。

于 2012-04-18T14:18:41.393 に答える
0

現在実行中のスレッドが使用しているDispatcherに関連付けられてInvoke()いる場合、このスレッドはブロックされるため、この場合はDispatcher.BeginInvoke()を使用して、非同期でジョブを実行します。

MSDN、Dispatcher.Invokeメソッド

Invokeは同期操作です。したがって、コールバックが戻るまで、制御は呼び出し元のオブジェクトに戻りません。

ところで、興味のあるだけで試してみてくださいDispatcherPriority.Send

于 2012-04-18T14:13:24.187 に答える
0

私はパーティーに 9 年遅れて参加しましたが、これはさらに簡単な解決策だと思います。プログレス バーの値が特定のしきい値に達するまで待ってから更新するだけです。私の例では、最大値の 5 分の 1 ごとにツールバーを更新します。

private static int progressBarMaxValue = -1;
private static int progressBarChunkSize = -1;

        public static void progressBarSetNotRealTimeValue(ProgressBar progressBar, int argNewValue)
        {
            if (progressBarMaxValue != -1)
            {
                if (argNewValue < progressBarChunkSize)
                {
                    //Threshold not reached yet, discard the new value.
                    return;
                }
                else
                {
                    //Allow the update, and set the next threshold higher.
                    progressBarChunkSize += progressBarChunkSize;
                }
            }

            if (Thread.CurrentThread.IsBackground)
            {
                progressBar.BeginInvoke(new Action(() =>
                {
                    if (progressBarMaxValue == -1)
                    {
                        progressBarMaxValue = progressBar.Maximum;
                        progressBarChunkSize = progressBar.Maximum / 5;
                    }

                    progressBar.Value = argNewValue;
                }));
            }
            else
            {
                progressBar.Value = argNewValue;
            }
        }
于 2021-08-13T16:49:39.837 に答える