it-swarm.com.de

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

Fragen Sie sich 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 dieses Aufrufs und dem einfachen Aufrufen von BeginInvoke() für einen Delegaten? oder sind sie dasselbe?

373
Nathan W

Meinen Sie damit Delegate.Invoke/BeginInvoke oder Control.Invoke/BeginInvoke?

  • Delegate.Invoke: Wird synchron auf demselben Thread ausgeführt.
  • Delegate.BeginInvoke: Wird in einem Threadpool-Thread asynchron 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 im UI-Thread ausgeführt und der aufrufende Thread wartet nicht auf den Abschluss.

In Tims Antwort wird erwähnt, wann Sie BeginInvoke verwenden möchten - obwohl es hauptsächlich auf Delegate.BeginInvoke abzielte, vermute ich.

Für Windows Forms-Apps würde ich vorschlagen, dass Sie normalerweise BeginInvoke verwenden. 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 sich das nächste Mal ansehen! Insbesondere sollten Sie keine Daten ändern, die der UI-Thread möglicherweise für Anzeigezwecke verwenden wird. Wenn Sie beispielsweise eine Person mit den Eigenschaften Vorname und Nachname haben und Folgendes ausgeführt haben:

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

dann wird auf der Benutzeroberfläche möglicherweise "Keyser Spacey" angezeigt. (Es besteht die Möglichkeit, dass "Kevin Soze" angezeigt wird, aber nur durch die Verrücktheit des Speichermodells.)

Wenn Sie diese Art von Problem nicht haben, ist Control.BeginInvoke jedoch einfacher zu finden und es wird vermieden, dass Ihr Hintergrund-Thread ohne triftigen Grund warten muss. Beachten Sie, dass das Windows Forms-Team garantiert hat, dass Sie Control.BeginInvoke "feuern und vergessen" können, d. H. Ohne jemals EndInvoke aufzurufen. Dies gilt nicht für asynchrone Anrufe im Allgemeinen: Normalerweise sollte jeder BeginXXX einen entsprechenden EndXXX-Anruf haben, normalerweise im Rückruf.

538
Jon Skeet

Aufbauend auf der Antwort von Jon Skeet kann es vorkommen, dass 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 Anruf Aufrufen das, was Sie möchten.

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

In diesen Fällen wäre das BeginInvoke nützlich. Wenn Sie es aufrufen, teilen Sie dem Delegaten mit, dass er beginnen soll, aber dann kann Ihr Thread andere Dinge parallel mit dem Delegaten ausführen.

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

42
Tim Stewart

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

  • BeginInvoke() plant die asynchrone Aktion für den GUI-Thread. Wenn die asynchrone Aktion geplant ist, wird der 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, den Sie an Invoke() übergeben, über out-Parameter oder einen Rückgabewert verfügen kann, während ein Delegat, den Sie an BeginInvoke() übergeben, dies nicht kann (Sie müssen EndInvoke zum Abrufen verwenden) die Ergebnisse).

24
Sujit

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

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

17
KMC

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

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

MSDN-Artikel

8
Aaron Palmer

Fügen Sie einfach hinzu, warum und wann Sie Invoke () verwenden sollen.

Sowohl Invoke () als auch BeginInvoke () stellen den von Ihnen angegebenen Code für den Dispatcher-Thread bereit.

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

Sie können beispielsweise Invoke () aufrufen, um einen Codeausschnitt auszuführen, in dem ein Dialogfeld OK/Abbrechen angezeigt wird. Nachdem der Benutzer auf eine Schaltfläche geklickt und der gemarshallte Code vollständig ist, wird die invoke () -Methode zurückgegeben, und Sie können auf die Antwort des Benutzers reagieren.

Siehe Pro WPF in C # Kapitel 31

7
Ingako