6

私は最近、彼らがあなたと良い警官/悪い警官を演じる、本当に悪いインタビューの1つを持っていました. 私が何を答えても、そのうちの 1 人には十分ではなく、私の自信は刻一刻と縮んでいました。私を本当に混乱させた彼の最後の質問は次のとおりです。

コントロールが InvokeRequired を必要とする場合、.Invoke または .BeginInvoke の実行に違いはありますか?

私がそれをどのように理解しているか、例を示しましょう:

public delegate string WorkLongDelegate(int i);

var del = new WorkLongDelegate(WorkLong);
var callback = new AsyncCallback(CallBack);
del.BeginInvoke(3000, callback, del);

public string WorkLong(int i)
{
      Thread.Sleep(i);
      return (string.Format("Work was done within {0} seconds.", i));            
}

private void CallBack(IAsyncResult ar)
{
    var del = (WorkLongDelegate) ar.AsyncState;
    SetText2(del.EndInvoke(ar));
}

private void SetText2(string s)
{
   if(InvokeRequired)
   {
       // What is the difference between BeginInvoke and Invoke in below?
       BeginInvoke(new MethodInvoker(() => textBox1.Text = s)); 
   }
   else
   {
       textBox1.Text = s;
   }
}

Invoke が実行されるまで UI スレッドを停止している間、BeginInvoke は非同期でそれを行うと述べました。しかし、それだけでは十分ではありませんでした。それにもかかわらず、代わりに Invoke を使用した場合のパフォーマンスへの影響はわかりません。誰か教えてください。

4

3 に答える 3

14

InvokeUIスレッドを停止しません。UI スレッドが完了するまで、呼び出し元のスレッドが続行するのをブロックします。

つまり、問題は、UI の更新が完了する前にバックグラウンド操作を続行するかどうかです。通常、これ当てはまると思います。たとえば、進行状況レポートを UI に提供するだけの場合、UI スレッドがまだ追いついていないという理由だけで作業を停止したくはありません。

一方、UI スレッドから何かを取得する必要がある場合(これはかなりまれなことですが) は、Invoke代わりに使用することをお勧めします。BeginInvoke特別な理由がない限り、使用する必要があると思いますInvoke。しかし、どちらにしても、違いを理解する必要があります:)

于 2010-10-24T17:55:20.887 に答える
4

Invoke() の非常に明白な使用例は、戻り値が必要なメソッドを呼び出す必要がある場合です。これを提供できるのは Invoke() だけです。メソッドの戻り値である Object を返します。

弱いものは、UI スレッドが追いつくよりもはるかに速い速度でワーカー スレッドが結果を生成している場合です。Invoke() を使用するとワーカーが抑制され、invoke リストは無制限に大きくなりません。ただし、これはより大きな問題に対する応急処置に過ぎず、人間が認識できる速度よりも速く UI を更新しても意味がありません。人間の目には 40 ミリ秒に 1 回が滑らかに見えます。UI スレッドが結果のコレクションを処理するのにまだ時間がかかりすぎる場合は、引き続き Invoke() を使用する必要があります。このような問題が発生する典型的な兆候は、UI スレッドがフリーズすることです。これは、invoke リクエストによって完全に圧倒されるため、描画やマウスおよびキーボード イベントへの応答ができなくなります。また、ワーカーの実行が完了した後、UI スレッドがしばらく応答しなくなり、バックログの処理に忙殺されました。

もう 1 つのケースは、BeginInvoke() に渡すオブジェクトのロック要件です。Invoke() を使用する場合、ロックは必要ありません。UI スレッドとワーカー スレッドは同時にオブジェクトにアクセスできません。BeginInvoke の場合とは異なり、モータリングを続け、スレッドが同じオブジェクトを使用し続ける場合は、UI スレッドとワーカーの両方でロックを使用してオブジェクトを保護する必要があります。そのロックがワーカーの進行を妨げている場合は、Invoke() を使用することもできます。これは非常に珍しいことで、メイン スレッドがデリゲートの実行を開始するのにかなりの時間がかかります。また、ロックの必要がないように、呼び出し後にオブジェクトの新しいインスタンスを作成することを常にお勧めします。

于 2010-10-24T18:16:21.447 に答える
0

当然、asnyc バージョンを使用している場合、バックグラウンド スレッドはコンテキスト スイッチを待たずにすぐに続行できます。

通常、私が理解していることから、これは(バックグラウンドスレッドの場合)より高速になるはずです。

于 2010-10-24T17:43:21.677 に答える