web-dev-qa-db-fra.com

C # dois-je créer un ou plusieurs travailleurs en arrière-plan?

Je suis un de ces programmeurs accidentels, donc je n'ai pas beaucoup de connaissances sur les meilleures pratiques de programmation.

J'ai une application qui utilise actuellement 4 Background Worker.

Alors je les déclare:

private BackgroundWorker bw1;
private BackgroundWorker bw2;
private BackgroundWorker bw3;
private BackgroundWorker bw4;

Puis configurez-les:

bw1 = new BackgroundWorker();
bw1.WorkerReportsProgress = true;
bw1.DoWork += new DoWorkEventHandler(bw1_DoWork);
bw1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw1_RunWorkerCompleted);
bw1.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw2 = new BackgroundWorker();
bw2.WorkerReportsProgress = true;
bw2.DoWork += new DoWorkEventHandler(bw2_DoWork);
bw2.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw2_RunWorkerCompleted);
bw2.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw3 = new BackgroundWorker();
bw3.WorkerReportsProgress = true;
bw3.DoWork += new DoWorkEventHandler(bw3_DoWork);
bw3.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw3_RunWorkerCompleted);
bw3.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

bw4 = new BackgroundWorker();
bw4.WorkerReportsProgress = true;
bw4.DoWork += new DoWorkEventHandler(bw4_DoWork);
bw4.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw4_RunWorkerCompleted);
bw4.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

Et puis j'utilise bw1.RunWorkerAsync (), bw2.RunWorkerAsync (), etc.

Le truc, c'est que je ne les appelle jamais en même temps, ils sont appelés à un point différent de manière assez linéaire.

Ma question est donc la suivante: vaut-il mieux avoir de nombreux travailleurs d’arrière-plan «préconfigurés» ou en avoir un et modifier les événements DoWork et RunWorkerCompleted en fonction de ce que je souhaite que cela fasse?

23
Alex

D'un point de vue architectural, il est préférable de disposer d'un travailleur d'arrière-plan distinct pour chaque tâche en arrière-plan, sans lien logique avec une autre tâche de la classe. 

23
Maxim V. Pavlov

D'habitude, j'utilise des travailleurs d'arrière-plan selon un schéma assez différent. Au lieu de les définir tous en même temps au début, y compris leurs gestionnaires d'événements respectifs, je les crée à la volée lorsque je fais quelque chose qui en a besoin.

public void SomeEventHandlerMaybe(object sender, EventArgs e) {
  // do something

  var bw = new BackgroundWorker();
  bw.ReportsProgress = true;
  bw.DoWork += delegate {
    // do work. You can use locals from here
  };
  bw.ProgressChanged += delegate { ... };
  bw.RunWorkerCompleted += delegate {
    // do something with the results.
  };
  bw.RunWorkerAsync();
}

Quelque chose comme ca. L’avantage est que tout le code fait quelque chose avec ou dans l’arrière-plan au même endroit et dans le bon ordre également.

26
Joey

En règle générale, il est raisonnable d'utiliser plusieurs threads si cela permet une utilisation plus efficace des ressources sur votre système. Pour les tâches gourmandes en ressources processeur, un thread par cœur constitue un bon point de départ. Pour IO tâches intensives, vous pouvez certainement en avoir bien plus que cela.

Si vous avez la possibilité d'utiliser .NET 4, je chercherais dans Bibliothèque parallèle de tâches au lieu de BackgroundWorker. Par défaut, il prendra des décisions relativement intelligentes quant au nombre de threads à exécuter simultanément, en plus de fournir un modèle de programmation plus simple.

4
Eric J.

Faire votre traitement en utilisant BackgroundWorker signifie que vous le faites dans un thread séparé. Donc, si vous n'avez pas besoin du multithreading, vous n'avez pas besoin de travailleurs d'arrière-plan distincts. Si vous attendez la fin de chaque travail, vous ne pouvez avoir qu'un seul travailleur. Cela pourrait également supprimer une partie de la duplication de code ...

0
Amittai Shapira

Vous dirigez des travailleurs à des fins de calcul. Si le calcul d'un appel est utilisé ou dépend de quelque manière que ce soit, vous pouvez utiliser plus d'un opérateur pour obtenir de meilleures performances (en passant, il s'agit également d'un sujet à mesurer). Si vous avez juste besoin de 4 tâches et que vous les exécutez dans un thread séparé pour ne pas bloquer l'interface utilisateur principale, un opérateur est une très bonne solution.

0
Tigran