web-dev-qa-db-ja.com

Invoke()とBeginInvoke()の違いは何ですか

BeginInvoke()Invoke()の違いはなんでしょうか。

主にそれぞれが使用されるものです。

編集:スレッディングオブジェクトを作成することとその上でinvokeを呼び出すこととデリゲートでBeginInvoke()を呼び出すことの違いは何ですか?それともそれらは同じものですか?

369
Nathan W

あなたはDelegate.Invoke/BeginInvokeまたはControl.Invoke/BeginInvokeを意味しますか?

  • Delegate.Invoke:同じスレッド上で同期的に実行されます。
  • Delegate.BeginInvoke:スレッドプールスレッドで非同期に実行されます。
  • Control.Invoke:UIスレッドで実行されますが、呼び出しスレッドは続行する前に完了を待ちます。
  • Control.BeginInvoke:UIスレッド上で実行され、呼び出し側スレッドは完了を待ちません。

Timの答えは、BeginInvokeを使いたいと思うときに言及しています - それは主にDelegate.BeginInvokeを対象としていました、と私は思う。

Windowsフォームアプリケーションの場合、通常BeginInvokeを使用することをお勧めします。こうすれば、たとえば、デッドロックを心配する必要はありません。ただし、次に表示するときまでにUIが更新されていない可能性があることを理解する必要があります。特に、UIスレッドが表示目的で使用しようとしているデータを変更しないでください。たとえば、FirstNameプロパティとLastNameプロパティを持つPersonがあり、次のようにしたとします。

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を "fire and forget"の方法で、つまりEndInvokeを呼び出さずに使用できることを保証しています。これは一般に非同期呼び出しには当てはまりません。通常、すべてのBeginXXXには対応するEndXXX呼び出しがあり、通常はコールバックにあります。

534
Jon Skeet

Jon Skeetの返事を踏まえて、現在のスレッドが続行する前にデリゲートを呼び出してその実行が完了するのを待ちたい場合があります。そのような場合には、Invoke呼び出しがあなたが望むものです。

マルチスレッドアプリケーションでは、特にそのデリゲートがI/Oを実行する(デリゲートとスレッドがブロックされる可能性がある)場合は、スレッドがデリゲートの実行を終了するのを待機したくない場合があります。

そのような場合はBeginInvokeが役立ちます。それを呼び出すことによって、あなたはデリゲートに開始するように言っています、しかしあなたのスレッドはデリゲートと並行して他のことを自由に行うことができます。

BeginInvokeを使用するとコードの複雑さが増しますが、パフォーマンスの向上がその複雑さに見合う価値がある場合があります。

42
Tim Stewart

Control.Invoke()Control.BeginInvoke()の違いは、

  • BeginInvoke()はGUIスレッド上で非同期アクションをスケジュールします。非同期アクションがスケジュールされると、コードは続行されます。しばらくしてから(非同期のアクションがいつ実行されるのか正確にはわかりません)
  • Invoke()は(GUIスレッド上で)あなたの非同期アクションを実行し、あなたのアクションが完了するまで待ちます。

論理的な結論として、Invoke()に渡すデリゲートはout-parametersまたはreturn-valueを持つことができますが、BeginInvoke()に渡すデリゲートはできません(結果を取得するにはEndInvokeを使用する必要があります)。

24
Sujit

違いの影響を見るために、短くて実用的な例を示すためだけに

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)呼び出しの効果を示すことができます。

15
KMC

Delegate.BeginInvoke()は、デリゲートの呼び出しを非同期的にキューに入れて、ただちに制御を返します。 Delegate.BeginInvoke()を使用するときは、結果を取得するためにコールバックメソッドでDelegate.EndInvoke()を呼び出す必要があります。

Delegate.Invoke()は、同じスレッド内でデリゲートを同期的に呼び出します。

MSDN記事

8
Aaron Palmer

Invoke()を使用する理由とタイミングを追加するだけです。

Invoke()とBeginInvoke()はどちらも、指定したコードをディスパッチャスレッドにマーシャリングします。

ただし、BeginInvoke()とは異なり、Invoke()はディスパッチャがコードを実行するまでスレッドを停止します。 ユーザーが何らかのフィードバックを提供するまで非同期操作を一時停止する必要がある場合は、Invoke()を使用することをお勧めします。

たとえば、Invoke()を呼び出して、OK/Cancelダイアログボックスを表示するコードの断片を実行することができます。ユーザーがボタンをクリックして整列化されたコードが完了すると、invoke()メソッドが戻り、ユーザーの応答に応じて行動できます。

C#の第31章のPro WPFを参照してください。

7
Ingako