Quelle est la différence entre Invoke () et BeginInvoke ()

398

Vous vous demandez quelle est la différence entre BeginInvoke()et Invoke()sont?

Principalement à quoi chacun serait utilisé.

EDIT: Quelle est la différence entre créer un objet de thread et appeler invoquer dessus et simplement appeler BeginInvoke()un délégué? ou sont-ce la même chose?

Nathan W
la source

Réponses:

569

Voulez-vous dire Delegate.Invoke/ BeginInvokeou Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: S'exécute de manière synchrone, sur le même thread.
  • Delegate.BeginInvoke: S'exécute de manière asynchrone, sur un threadpoolthread.
  • Control.Invoke: S'exécute sur le thread d'interface utilisateur, mais le thread appelant attend la fin avant de continuer.
  • Control.BeginInvoke: S'exécute sur le thread d'interface utilisateur et le thread appelant n'attend pas la fin.

La réponse de Tim mentionne quand vous voudrez peut-être l'utiliser BeginInvoke- même si elle était principalement destinée à Delegate.BeginInvoke, je suppose.

Pour les applications Windows Forms, je suggère que vous devriez généralement utiliser BeginInvoke. De cette façon, vous n'avez pas à vous soucier des blocages, par exemple - mais vous devez comprendre que l'interface utilisateur n'a peut-être pas été mise à jour la prochaine fois que vous l'examinerez! En particulier, vous ne devez pas modifier les données que le thread d'interface utilisateur pourrait être sur le point d'utiliser à des fins d'affichage. Par exemple, si vous avez un Personavec FirstNameet des LastNamepropriétés, et que vous avez:

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

L'interface utilisateur pourrait bien finir par afficher "Keyser Spacey". (Il y a une chance extérieure qu'il puisse afficher "Kevin Soze" mais uniquement à travers l'étrangeté du modèle de mémoire.)

À moins que vous n'ayez ce genre de problème, cependant, il Control.BeginInvokeest plus facile de résoudre le problème et évitera à votre thread d'arrière-plan d'attendre sans raison valable. Notez que l'équipe Windows Forms a garanti que vous pouvez utiliser Control.BeginInvoked'une manière "tirer et oublier" - c'est-à-dire sans jamais appeler EndInvoke. Ce n'est pas le cas des appels asynchrones en général: normalement, chaque BeginXXX doit avoir un appel EndXXX correspondant, généralement dans le rappel.

Jon Skeet
la source
4
Alors pourquoi ppl utiliserait-il Invoke plutôt que BeingInvoke? Ne devrait-il pas y avoir certains avantages à utiliser Invoke? Les deux exécutent des processus en arrière-plan, juste que l'un est sur le même thread, l'autre sur un thread différent?
yeeen
2
@ Jon: Pendant que j'utilise Dispatcher.BeginInvoke mon code fonctionne bien et dans Dispatcher.Invoke mon application me fait attendre quelques secondes puis initialise tous les contrôles puis se lance, Pouvez-vous m'aider à savoir exactement où je suis resté ?
SharpUrBrain
6
@SharpUrBrain: Control.BeginInvoke est en quelque sorte l'équivalent de Dispatcher.BeginInvoke, mais pour WinForms (alors que Dispatcher est pour WPF et Silverlight).
Jon Skeet
4
@SharpUrBrain: Je vous suggère de poser une question spécifique plutôt que de continuer dans les commentaires - et bien sûr de vérifier si la même question a déjà été posée par quelqu'un d'autre en premier.
Jon Skeet
2
@AZ: Oui, par "sur le thread d'interface utilisateur", il signifie sur le "thread d'interface utilisateur" particulier qui possède la poignée de ce contrôle particulier. En règle générale, il n'y a qu'un seul thread d'interface utilisateur, mais il est possible d'avoir plusieurs threads d'interface utilisateur, et dans les applications avancées, il existe des raisons pour lesquelles vous en voudriez. Techniquement, n'importe quel thread (normal?) Pourrait démarrer une pompe de message d'interface utilisateur et devenir un thread d'interface utilisateur - et pourrait plus tard arrêter la pompe de message et ne plus être un thread d'interface utilisateur. (Je suppose que ce n'est pas quelque chose à essayer sur un thread threadpool, cependant.)
Rob Parker
46

En s'appuyant sur la réponse de Jon Skeet, il y a des moments où vous souhaitez invoquer un délégué et attendre que son exécution se termine avant que le thread actuel ne continue. Dans ces cas, l'appel Invoke est ce que vous voulez.

Dans les applications multithread, il se peut que vous ne souhaitiez pas qu'un thread attende un délégué pour terminer l'exécution, en particulier si ce délégué effectue des E / S (ce qui pourrait rendre le délégué et votre bloc de threads).

Dans ces cas, BeginInvoke serait utile. En l'appelant, vous dites au délégué de démarrer, mais votre thread est libre de faire d'autres choses en parallèle avec le délégué.

L'utilisation de BeginInvoke augmente la complexité de votre code mais il y a des moments où l'amélioration des performances vaut la complexité.

Tim Stewart
la source
27

La différence entre Control.Invoke()et Control.BeginInvoke()est,

  • BeginInvoke()planifiera l'action asynchrone sur le thread GUI. Lorsque l'action asynchrone est planifiée, votre code continue. Quelque temps plus tard (vous ne savez pas exactement quand) votre action asynchrone sera exécutée
  • Invoke() exécutera votre action asynchrone (sur le thread GUI) et attendra que votre action soit terminée.

Une conclusion logique est qu'un délégué auquel vous passez Invoke()peut avoir des paramètres de sortie ou une valeur de retour, tandis qu'un délégué BeginInvoke()auquel vous passez ne peut pas (vous devez utiliser EndInvoke pour récupérer les résultats).

Sujit
la source
20

Juste pour donner un court exemple pratique pour voir un effet de leur différence

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

Si vous utilisez BeginInvoke , MessageBox apparaît simultanément à la mise à jour du texte. Si vous utilisez Invoke , MessageBox apparaît après les 3 secondes de sommeil. Par conséquent, montrant l'effet d'un appel asynchrone ( BeginInvoke ) et synchrone ( Invoke ).

KMC
la source
9

Delegate.BeginInvoke () met en file d'attente de manière asynchrone l'appel d'un délégué et renvoie immédiatement le contrôle. Lorsque vous utilisez Delegate.BeginInvoke (), vous devez appeler Delegate.EndInvoke () dans la méthode de rappel pour obtenir les résultats.

Delegate.Invoke () appelle de manière synchrone le délégué dans le même thread.

Article MSDN

Aaron Palmer
la source
8

Il suffit d'ajouter pourquoi et quand utiliser Invoke ().

Invoke () et BeginInvoke () rassemblent le code que vous spécifiez sur le thread du répartiteur.

Mais contrairement à BeginInvoke (), Invoke () bloque votre thread jusqu'à ce que le répartiteur exécute votre code. Vous souhaiterez peut-être utiliser Invoke () si vous devez suspendre une opération asynchrone jusqu'à ce que l'utilisateur ait fourni une sorte de rétroaction.

Par exemple, vous pouvez appeler Invoke () pour exécuter un extrait de code qui affiche une boîte de dialogue OK / Annuler. Une fois que l'utilisateur a cliqué sur un bouton et que votre code marshalé est terminé, la méthode invoke () revient et vous pouvez réagir à la réponse de l'utilisateur.

Voir Pro WPF dans C # chapitre 31

Ingako
la source