Was ist der Unterschied zwischen Invoke () und BeginInvoke ()

398

Ich frage mich nur, was der Unterschied zwischen BeginInvoke()und Invoke()ist?

Hauptsächlich wofür jeder verwendet werden würde.

BEARBEITEN: Was ist der Unterschied zwischen dem Erstellen eines Threading-Objekts und dem Aufrufen eines Aufrufs und dem Aufrufen BeginInvoke()eines Delegaten? oder sind sie dasselbe?

Nathan W.
quelle

Antworten:

568

Meinst du Delegate.Invoke/ BeginInvokeoder Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: Wird synchron im selben Thread ausgeführt.
  • Delegate.BeginInvoke: Wird asynchron in einem threadpoolThread ausgeführt.
  • Control.Invoke: Wird auf dem UI-Thread ausgeführt, aber der aufrufende Thread wartet auf den Abschluss, bevor er fortfährt.
  • Control.BeginInvoke: Wird auf dem UI-Thread ausgeführt und der aufrufende Thread wartet nicht auf den Abschluss.

Tims Antwort erwähnt, wann Sie sie verwenden möchten BeginInvoke- obwohl sie vermutlich hauptsächlich darauf ausgerichtet Delegate.BeginInvokewar.

Für Windows Forms-Apps würde ich empfehlen, dass Sie normalerweise verwenden BeginInvoke. Auf diese Weise müssen Sie sich zum Beispiel keine Gedanken über Deadlocks machen - aber Sie müssen verstehen, dass die Benutzeroberfläche möglicherweise nicht aktualisiert wurde, wenn Sie sie das nächste Mal betrachten! Insbesondere sollten Sie keine Daten ändern, die der UI-Thread möglicherweise für Anzeigezwecke verwendet. Wenn Sie beispielsweise ein Personwith FirstNameund LastNameEigenschaften haben und Folgendes getan haben:

person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";

Dann zeigt die Benutzeroberfläche möglicherweise "Keyser Spacey" an. (Es besteht die Möglichkeit, dass "Kevin Soze" angezeigt wird, jedoch nur durch die Verrücktheit des Speichermodells.)

Es sei denn, Sie haben diese Art von Problem, ist jedoch Control.BeginInvokeeinfacher zu beheben und verhindert, dass Ihr Hintergrund-Thread ohne guten Grund warten muss. Beachten Sie, dass das Windows Forms-Team garantiert hat, dass Sie es Control.BeginInvoke"Feuer und Vergessen" verwenden können - dh ohne jemals anzurufen EndInvoke. Dies gilt im Allgemeinen nicht für asynchrone Aufrufe: Normalerweise sollte jeder BeginXXX einen entsprechenden EndXXX-Aufruf haben, normalerweise im Rückruf.

Jon Skeet
quelle
4
Warum sollte ppl dann Invoke über BeingInvoke verwenden? Sollte es nicht einige Vorteile gegenüber der Verwendung von Invoke geben? Beide führen Prozesse im Hintergrund aus, nur dass sich einer auf demselben Thread befindet, der andere auf einem anderen Thread?
Yeeen
2
@Jon: Während ich Dispatcher.BeginInvoke verwende, funktioniert mein Code einwandfrei und in Dispatcher.Invoke meine Anwendung, sodass ich einige Sekunden warten muss, dann werden alle Steuerelemente initialisiert und dann gestartet. Können Sie mir bitte helfen, genau herauszufinden, an welcher Stelle ich feststeckte? ?
SharpUrBrain
6
@SharpUrBrain: Control.BeginInvoke entspricht in etwa Dispatcher.BeginInvoke, jedoch für WinForms (während Dispatcher für WPF und Silverlight gilt).
Jon Skeet
4
@SharpUrBrain: Ich würde vorschlagen, dass Sie eine bestimmte Frage stellen, anstatt in Kommentaren fortzufahren - und natürlich prüfen, ob dieselbe Frage bereits von jemand anderem gestellt wurde.
Jon Skeet
2
@AZ: Ja, mit "auf dem UI-Thread" meint er auf dem bestimmten "UI-Thread", dem das Handle dieses bestimmten Steuerelements gehört. Normalerweise gibt es nur einen UI-Thread, aber es ist möglich, mehrere UI-Threads zu haben, und in erweiterten Anwendungen gibt es Gründe, warum Sie sie möchten. Technisch gesehen könnte jeder (normale?) Thread eine UI-Nachrichtenpumpe starten und zu einem UI-Thread werden - und später die Nachrichtenpumpe herunterfahren und kein UI-Thread mehr sein. (Ich nehme an, das ist nicht etwas, um einen Threadpool-Thread anzuprobieren.)
Rob Parker
46

Aufbauend auf Jon Skeets Antwort gibt es Zeiten, in denen Sie einen Delegaten aufrufen und warten möchten, bis seine Ausführung abgeschlossen ist, bevor der aktuelle Thread fortgesetzt wird. In diesen Fällen ist der Aufruf von Invoke genau das, was Sie wollen.

In Multithreading-Anwendungen möchten Sie möglicherweise nicht, dass ein Thread auf einen Delegaten wartet, um die Ausführung zu beenden, insbesondere wenn dieser Delegat E / A ausführt (wodurch der Delegat und Ihr Thread blockiert werden könnten).

In diesen Fällen wäre BeginInvoke hilfreich. Wenn Sie es aufrufen, weisen Sie den Delegaten an, zu starten, aber dann kann Ihr Thread andere Dinge parallel zum Delegaten ausführen.

Die Verwendung von BeginInvoke erhöht die Komplexität Ihres Codes, aber manchmal ist die verbesserte Leistung die Komplexität wert.

Tim Stewart
quelle
27

Der Unterschied zwischen Control.Invoke()und Control.BeginInvoke()ist,

  • BeginInvoke()plant die asynchrone Aktion im GUI-Thread. Wenn die asynchrone Aktion geplant ist, wird Ihr Code fortgesetzt. Einige Zeit später (Sie wissen nicht genau wann) wird Ihre asynchrone Aktion ausgeführt
  • Invoke() führt Ihre asynchrone Aktion (im GUI-Thread) aus und wartet, bis Ihre Aktion abgeschlossen ist.

Eine logische Schlussfolgerung ist, dass ein Delegat, an den Sie übergeben, Invoke()Out-Parameter oder einen Rückgabewert haben kann, während ein Delegat, an den Sie übergeben, BeginInvoke()dies nicht kann (Sie müssen EndInvoke verwenden, um die Ergebnisse abzurufen).

Sujit
quelle
20

Nur um ein kurzes, funktionierendes Beispiel zu geben, um einen Effekt ihres Unterschieds zu sehen

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");
}

Wenn Sie BeginInvoke verwenden , wird MessageBox gleichzeitig mit der Textaktualisierung angezeigt . Wenn Sie Invoke verwenden , wird die MessageBox nach dem 3-Sekunden-Ruhezustand angezeigt. Daher wird der Effekt eines asynchronen ( BeginInvoke ) und eines synchronen ( Invoke ) Aufrufs angezeigt .

KMC
quelle
9

Delegate.BeginInvoke () stellt den Aufruf eines Delegaten asynchron in die Warteschlange und gibt die Kontrolle sofort zurück. Wenn Sie Delegate.BeginInvoke () verwenden, sollten Sie Delegate.EndInvoke () in der Rückrufmethode aufrufen, um die Ergebnisse zu erhalten.

Delegate.Invoke () ruft den Delegaten synchron im selben Thread auf.

MSDN-Artikel

Aaron Palmer
quelle
8

Fügen Sie einfach hinzu, warum und wann Invoke () verwendet werden soll.

Sowohl Invoke () als auch BeginInvoke () marshallen den Code, den Sie für den Dispatcher-Thread angegeben haben.

Im Gegensatz zu BeginInvoke () blockiert Invoke () Ihren Thread, bis der Dispatcher Ihren Code ausführt. Möglicherweise möchten Sie Invoke () verwenden, wenn Sie einen asynchronen Vorgang anhalten müssen, bis der Benutzer eine Art Feedback gegeben hat.

Sie können beispielsweise Invoke () aufrufen, um einen Codeausschnitt auszuführen, der ein Dialogfeld OK / Abbrechen anzeigt. Nachdem der Benutzer auf eine Schaltfläche geklickt hat und Ihr gemarshallter Code abgeschlossen ist, kehrt die invoke () -Methode zurück und Sie können auf die Antwort des Benutzers reagieren.

Siehe Pro WPF in C # Kapitel 31

Ingako
quelle