回答:
Delegate.Invoke
/ BeginInvoke
またはControl.Invoke
/の意味BeginInvoke
ですか?
Delegate.Invoke
:同じスレッドで同期的に実行されます。Delegate.BeginInvoke
:threadpool
スレッドで非同期的に実行されます。Control.Invoke
:UIスレッドで実行されますが、呼び出しスレッドは完了する前に待機してから続行します。Control.BeginInvoke
:UIスレッドで実行され、呼び出しスレッドは完了を待機しません。ティムの答えはあなたが使いたいかもしれないときに言及しています BeginInvoke
、それは主に目指していたが- Delegate.BeginInvoke
、私は疑います。
Windowsフォームアプリの場合、通常はを使用することをお勧めしますBeginInvoke
。これにより、たとえばデッドロックを心配する必要がなくなります。ただし、次に見たときにはUIが更新されていない可能性があることを理解する必要があります。特に、UIスレッドが表示目的で使用する可能性のあるデータは変更しないでください。たとえば、Person
with FirstName
とLastName
プロパティがあり、次の場合:
person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";
その場合、UIは「Keyser Spacey」を表示することになります。(「Kevin Soze」が表示される可能性はありますが、記憶モデルの奇妙さによってのみ可能です。)
ただし、この種の問題がない限り、Control.BeginInvoke
簡単に修正でき、バックグラウンドスレッドが正当な理由なしに待機する必要がなくなります。WindowsフォームチームはControl.BeginInvoke
、「ファイアアンドフォーゲット」の方法、つまりを呼び出さなくても使用できることを保証していますEndInvoke
。これは一般的な非同期呼び出しには当てはまりません。通常、すべてのBeginXXXには、通常、コールバック内に、対応するEndXXX呼び出しが必要です。
Jon Skeetの応答に基づいて、デリゲートを呼び出し、現在のスレッドが続行する前にその実行が完了するのを待機したい場合があります。これらの場合、Invoke呼び出しが必要です。
マルチスレッドアプリケーションでは、特にデリゲートがI / Oを実行する(デリゲートとスレッドがブロックされる可能性がある)場合に、スレッドがデリゲートの実行を完了するのを待たないようにする必要があります。
これらの場合、BeginInvokeが役立ちます。それを呼び出すことにより、デリゲートに開始するように伝えますが、スレッドはデリゲートと並行して他のことを自由に実行できます。
BeginInvokeを使用すると、コードの複雑さが増しますが、パフォーマンスの向上が複雑に見合う場合もあります。
違いControl.Invoke()
とControl.BeginInvoke()
され、
BeginInvoke()
GUIスレッドで非同期アクションをスケジュールします。非同期アクションがスケジュールされると、コードが続行されます。しばらくして(正確なタイミングはわかりません)非同期アクションが実行されますInvoke()
(GUIスレッドで)非同期アクションを実行し、アクションが完了するまで待機します。論理的な結論としては、渡すデリゲートInvoke()
はout-parametersまたはreturn-value BeginInvoke()
を持つことができますが、渡すデリゲートはできません(結果を取得するにはEndInvokeを使用する必要があります)。
違いの効果を確認するための短い実用的な例を示すためだけに
new Thread(foo).Start();
private void foo()
{
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate()
{
myTextBox.Text = "bing";
Thread.Sleep(TimeSpan.FromSeconds(3));
});
MessageBox.Show("done");
}
BeginInvokeを使用する場合、MessageBoxはテキストの更新と同時にポップします。Invokeを使用する場合、MessageBoxは3秒のスリープ後にポップします。したがって、非同期(BeginInvoke)および同期(Invoke)呼び出しの効果を示します。
Invoke()を使用する理由と時期を追加するだけです。
Invoke()とBeginInvoke()はどちらも、指定したコードをディスパッチャスレッドにマーシャリングします。
ただし、BeginInvoke()とは異なり、Invoke()は、ディスパッチャーがコードを実行するまでスレッドを停止します。ユーザーが何らかのフィードバックを提供するまで非同期操作を一時停止する必要がある場合は、Invoke()を使用できます。
たとえば、Invoke()を呼び出して、[OK /キャンセル]ダイアログボックスを表示するコードスニペットを実行できます。ユーザーがボタンをクリックしてマーシャリングされたコードが完了すると、invoke()メソッドが返され、ユーザーの応答に基づいてアクションを実行できます。
C#の第31章のPro WPFを参照してください