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


398

ただ、どのような違い不思議BeginInvoke()Invoke()されていますか?

主にそれぞれが何のために使われるか。

編集:スレッド化オブジェクトを作成することと、それに対してinvokeを呼び出すこととBeginInvoke()、デリゲートを呼び出すことの違いは何ですか?またはそれらは同じものですか?

回答:


568

Delegate.Invoke/ BeginInvokeまたはControl.Invoke/の意味BeginInvokeですか?

  • Delegate.Invoke:同じスレッドで同期的に実行されます。
  • Delegate.BeginInvokethreadpoolスレッドで非同期的に実行されます。
  • Control.Invoke:UIスレッドで実行されますが、呼び出しスレッドは完了する前に待機してから続行します。
  • Control.BeginInvoke:UIスレッドで実行され、呼び出しスレッドは完了を待機しません。

ティムの答えはあなたが使いたいかもしれないときに言及しています BeginInvoke、それは主に目指していたが- Delegate.BeginInvoke、私は疑います。

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

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呼び出しが必要です。


4
では、なぜpplはBeingInvokeではなくInvokeを使用するのでしょうか。Invokeを使用するよりもいくつかの利点があるべきではありません。どちらもバックグラウンドでプロセスを実行しますが、一方は同じスレッドにあり、もう一方は異なるスレッドにありますか?
yeeen

2
@ジョン:Dispatcher.BeginInvokeを使用している間、コードは正常に機能し、Dispatcher.Invokeでアプリケーションを数秒間待機させてから、すべてのコントロールを初期化してから起動します?
SharpUrBrain、2011年

6
@SharpUrBrain:Control.BeginInvokeは、Dispatcher.BeginInvokeと同等の機能ですが、WinFormsの場合(DispatcherはWPFおよびSilverlightの場合)。
Jon Skeet、

4
@SharpUrBrain:コメントを続けるのではなく、特定の質問をすることをお勧めします-もちろん、同じ質問が他の誰かによってすでに最初に行われたかどうかを確認してください。
ジョンスキート、

2
@AZ:はい、「UIスレッド上」とは、特定のコントロールのハンドルを所有する特定の「UIスレッド」を意味します。通常、UIスレッドは1つだけですが、複数のUIスレッドを使用することも可能であり、高度なアプリケーションでは、それらが必要になる理由があります。技術的には、任意の(通常の)スレッドがUIメッセージポンプを開始してUIスレッドになり、後でメッセージポンプをシャットダウンしてUIスレッドでなくなる可能性があります。(ただし、これはスレッドプールスレッドで試してみるものではないと思います。)
Rob Parker

46

Jon Skeetの応答に基づいて、デリゲートを呼び出し、現在のスレッドが続行する前にその実行が完了するのを待機したい場合があります。これらの場合、Invoke呼び出しが必要です。

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

これらの場合、BeginInvokeが役立ちます。それを呼び出すことにより、デリゲートに開始するように伝えますが、スレッドはデリゲートと並行して他のことを自由に実行できます。

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


27

違いControl.Invoke()Control.BeginInvoke()され、

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

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


20

違いの効果を確認するための短い実用的な例を示すためだけに

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


9

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

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

MSDN記事


8

Invoke()を使用する理由と時期を追加するだけです。

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

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

たとえば、Invoke()を呼び出して、[OK /キャンセル]ダイアログボックスを表示するコードスニペットを実行できます。ユーザーがボタンをクリックしてマーシャリングされたコードが完了すると、invoke()メソッドが返され、ユーザーの応答に基づいてアクションを実行できます。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.