2010-05-19 6 views
3

Quelle est la différence entre les options 1 et 2 dans ce qui suit?Diffrence entre BackgroundWorker.ReportProgress() et Control.BeginInvoke()

private void BGW_DoWork(object sender, DoWorkEventArgs e) 
    { 
     for (int i=1; i<=100; i++) 
     { 
      string txt = i.ToString(); 
      if (Test_Check.Checked) 
       //OPTION 1 
       Test_BackgroundWorker.ReportProgress(i, txt); 
      else 
       //OPTION 2 
       this.BeginInvoke((Action<int, string>)UpdateGUI, 
            new object[] {i, txt}); 
     } 
    } 

    private void BGW_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     UpdateGUI(e.ProgressPercentage, (string)e.UserState); 
    } 

    private void UpdateGUI(int percent, string txt) 
    { 
     Test_ProgressBar.Value = percent; 
     Test_RichTextBox.AppendText(txt + Environment.NewLine); 
    } 

regardant réflecteur, le Control.BeginInvoke() semble utiliser:

this.FindMarshalingControl().MarshaledInvoke(this, method, args, 1); 

qui semble éventuellement appeler des fonctions natives comme PostMessage(), ne pouvait pas comprendre exactement le flux de réflecteur (compilateur satanés optimisations goto)

Alors que BackgroundWorker.Invoke() semble utiliser:

this.asyncOperation.Post(this.progressReporter, args); 

qui semble appeler éventuellement ThreadPool.QueueUserWorkItem()

(je suis juste deviner ce sont la fonction correspondante appelle à chaque cas.) Si je comprends bien, en utilisant la ThreadPool ne garantirait pas l'ordre d'exécution alors que l'utilisation de la Poste mécanisme serait. Peut-être que ce serait une différence potentielle? (EDIT - Je n'ai pas pu synthétiser une telle situation - l'ordre d'appel semble être conservé dans les deux cas, au moins dans mes tests simples.)

Merci!

Répondre

2

Les deux sont identiques. L'appel que vous voyez dans BackgroundWorker utilise SynchronizationContext. En effet, l'implémentation par défaut de la méthode Post() utilise le pool de threads, mais lors du démarrage d'une application Windows Forms, le contexte de synchronisation par défaut est remplacé par WindowsFormsSynchronizationContext, qui appelle en réalité Control.BeginInvoke().

2

Une grande différence est que Control.Invoke va bloquer jusqu'à ce que l'appel UpdateGUI a été exécuté et complété, alors que BackgroundWorker.ReportProgress se pas bloc (il retournera immédiatement, avant le BackgroundWorker déclenche l'événement).

Si vous voulez qu'ils se comportent de la même manière, appelez le Control.BeginInvoke (qui ne bloque pas) à la place.

+0

Merci, mais il n'a pas été mon intention - je vient de revoir la question –

+0

Ma réponse est la même chose. ReportProgress est asynchrone, Control.Invoke est synchrone. Dans le cas d'une barre de progression, choisir l'un ou l'autre n'aurait probablement aucun effet notable. Si vous utilisez ReportProgress, la mise à jour de l'interface graphique sera presque instantanée de toute façon - la seule raison pour laquelle elle ne serait pas si votre formulaire est occupé à traiter un tas d'autres événements en même temps. – MusiGenesis

+0

Oui, mais je demande maintenant à propos de la différence entre ReportProgress et * BeginInvoke * –

0

J'ai trouvé une différence significative. Fermer le formulaire pendant que le BGW est en cours d'exécution provoquera this.Invoke() et this.BeginInvoke() pour lancer une ObjectDisposedException. Le mécanisme BGW ReportProgress contourne cela. Pour profiter du meilleur des deux mondes, le motif suivant fonctionne bien

public partial class MyForm : Form 
{ 
    private void InvokeViaBgw(Action action) 
    { 
     Packing_Worker.ReportProgress(0, action); 
    } 

    private void BGW_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     if (this.IsDisposed) return; //You are on the UI thread now, so no race condition 

     var action = (Action)e.UserState; 
     action(); 
    } 

    private private void BGW_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //Sample usage: 
     this.InvokeViaBgw(() => MyTextBox.Text = "Foo"); 
    } 
} 
Questions connexes