web-dev-qa-db-fra.com

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

Je me demandais simplement quelle était la différence entre BeginInvoke() et Invoke()?

Principalement pour quoi chacun serait utilisé.

EDIT: Quelle est la différence entre la création d’un objet thread et l’appel d’appel sur cet objet et le simple appel de BeginInvoke() sur un délégué? ou sont-ils la même chose?

373
Nathan W

Voulez-vous dire Delegate.Invoke/BeginInvoke ou 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 thread de pool de threads.
  • Control.Invoke: s'exécute sur le thread d'interface utilisateur, mais le thread d'appel attend son achèvement avant de continuer.
  • Control.BeginInvoke: s'exécute sur le thread d'interface utilisateur et le thread appelant n'attend pas son achèvement.

La réponse de Tim mentionne le moment où vous souhaitez utiliser BeginInvoke - bien que le programme soit principalement destiné à Delegate.BeginInvoke, je suppose.

Pour les applications Windows Forms, je suggérerais que vous deviez généralement utiliser BeginInvoke. Ainsi, vous n'avez pas besoin de vous inquiéter de l'impasse, par exemple, mais vous devez comprendre que l'interface utilisateur n'a peut-être pas été mise à jour au moment de votre prochaine consultation! En particulier, vous ne devez pas modifier les données que le thread d'interface utilisateur est sur le point d'utiliser à des fins d'affichage. Par exemple, si vous avez une personne avec les propriétés Prénom et Nom, et que vous l’avez fait:

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

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

Cependant, à moins que vous n'ayez ce type de problème, Control.BeginInvoke soit plus facile à résoudre 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.BeginInvoke de manière "feu et oublie" - c’est-à-dire sans jamais appeler EndInvoke. Ce n'est pas vrai des appels asynchrones en général: normalement chaque BeginXXX doit avoir un appel EndXXX correspondant, généralement dans le rappel.

538
Jon Skeet

En se basant sur la réponse de Jon Skeet, il est parfois nécessaire d'appeler un délégué et d'attendre la fin de son exécution pour que le thread en cours continue. Dans ces cas, l'appel Invoke est ce que vous voulez.

Dans les applications multithreading, vous pouvez ne pas vouloir qu'un thread attende qu'un délégué termine son exécution, surtout 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 commencer 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 l'amélioration des performances en vaut parfois la peine.

42
Tim Stewart

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

  • BeginInvoke() planifiera l'action asynchrone sur le thread d'interface graphique. Une fois l'action asynchrone programmé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 d'interface graphique) et attendra que votre action soit terminée.

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

24
Sujit

Juste pour donner un exemple court et 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, montrer l'effet d'un appel asynchrone (BeginInvoke) et synchrone (Invoke).

17
KMC

Delegate.BeginInvoke () met en file d'attente asynchrone l'appel d'un délégué et renvoie le contrôle immédiatement. 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

8
Aaron Palmer

Ajoutez juste pourquoi et quand utiliser Invoke ().

Invoke () et BeginInvoke () marshal le code que vous spécifiez pour le thread de répartition.

Mais contrairement à BeginInvoke (), Invoke () bloque votre thread jusqu'à ce que le répartiteur exécute votre code. Vous pouvez utiliser Invoke () si vous devez suspendre une opération asynchrone jusqu'à ce que l'utilisateur fournisse une sorte de retour.

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 () est renvoyée et vous pouvez agir en fonction de la réponse de l'utilisateur.

Voir Pro WPF en C # chapitre 31

7
Ingako