BackgroundWorker vs Thread d'arrière-plan

j'ai une question de style sur le choix de l'implémentation du thread d'arrière-plan que je devrais utiliser sur une application windows form. Actuellement j'ai un BackgroundWorker sur une forme qui a une boucle infinie (while(true)) . Dans cette boucle, j'utilise WaitHandle.WaitAny pour garder le fil qui ronfle jusqu'à ce que quelque chose d'intéressant arrive. L'un des événements les poignées j'attends, c'est un " StopThread événement " pour que je puisse sortir de la boucle. Cet événement est signalé lors de mon substituée Form.Dispose() .

j'ai lu quelque part que BackgroundWorker est vraiment destiné aux opérations que vous ne voulez pas lier L'UI avec et avoir une fin finie - comme le téléchargement d'un fichier, ou le traitement d'une séquence d'articles. Dans ce cas, la "fin" est inconnue, et seulement lorsque la fenêtre est fermée. Donc serait-il plus approprié pour moi d'utiliser un Thread d'arrière-plan au lieu de BackgroundWorker à cette fin?

151
demandé sur Naser Asadi 2009-10-02 02:25:52

11 réponses

d'après ma compréhension de votre question, vous utilisez un BackgroundWorker comme fil de discussion standard.

la raison pour laquelle BackgroundWorker est recommandé pour les choses que vous ne voulez pas attacher le fil UI est parce qu'il expose quelques événements agréables en faisant le développement de Win Forms.

des événements comme RunWorkerCompleted pour signaler quand le thread a terminé ce qu'il devait faire, et l'événement ProgressChanged pour mettre à jour l'interface graphique sur la progression des threads.

donc si vous ne sont pas faire usage de ces, Je ne vois pas de mal à utiliser un filetage standard pour ce que vous devez faire.

76
répondu ParmesanCodice 2013-08-04 08:55:11

quelques-unes de mes pensées...

  1. Utiliser BackgroundWorker si vous avez une seule tâche qui s'exécute en arrière-plan et besoin d'interagir avec l'INTERFACE utilisateur. La tâche de regrouper les appels de données et de méthodes dans le thread de L'interface utilisateur est gérée automatiquement par le biais de son modèle basé sur les événements. Eviter le BackgroundWorker si...
    • votre assemblée n'ont pas ou n'interagit pas directement avec l'INTERFACE utilisateur,
    • vous avez besoin le fil doit être un fil à l'avant-plan, ou
    • vous devez manipuler la priorité du fil.
  2. Utiliser un pool de threads fil lorsque l'efficacité est souhaitée. Le ThreadPool permet d'éviter les frais généraux associés à la création, au démarrage et à l'arrêt des threads. Évitez D'utiliser le ThreadPool si...
    • la tâche s'exécute pour la durée de vie de votre application,
    • vous avez besoin de la thread un thread de premier plan,
    • vous devez manipuler la priorité du fil, ou
    • vous avez besoin du fil pour avoir une identité fixe (avorter, suspendre, découvrir).
  3. utilisez la classe Thread pour les tâches de longue durée et lorsque vous avez besoin de fonctionnalités offertes par un modèle de filetage formel, par exemple, le choix entre les fils de premier plan et de fond, le réglage de la priorité du filetage, contrôle fin sur l'exécution du fil, etc.
341
répondu Matt Davis 2011-09-22 13:12:11

à peu près ce que Matt Davis a dit, avec les points supplémentaires suivants:

pour moi, le principal différenciateur avec BackgroundWorker est la formation automatique de l'événement complété via le SynchronizationContext . Dans un contexte D'interface utilisateur, cela signifie que l'événement terminé s'allume sur le thread D'interface utilisateur, et peut donc être utilisé pour mettre à jour L'interface utilisateur. Il s'agit d'un différenciateur majeur si vous utilisez le BackgroundWorker dans un contexte D'UI.

les tâches exécutées via le ThreadPool ne peuvent pas être facilement annulé (Cela inclut ThreadPool . QueueUserWorkItem et les délégués exécutent de manière asynchrone). Ainsi, alors qu'il évite la tête de fil de spinup, si vous avez besoin d'annulation soit utiliser un BackgroundWorker ou (plus probablement en dehors de L'UI) de spin up un fil et garder une référence à elle de sorte que vous pouvez appeler Abort() .

11
répondu piers7 2013-05-17 17:16:27

vous aussi vous attachez un fil threadpool pour la vie de l'ouvrier de fond, qui peut être de préoccupation car il n'y a qu'un nombre fini d'entre eux. Je dirais que si vous ne créez le thread qu'une seule fois pour votre application (et n'utilisez aucune des fonctionnalités de background worker), alors utilisez un thread, plutôt qu'un backgroundworker/threadpool thread.

10
répondu Matt 2009-10-02 00:08:35

vous savez, parfois, il est juste plus facile de travailler avec un travailleur de fond peu importe si vous utilisez des formulaires Windows, WPF ou n'importe quelle technologie. La partie soignée à propos de ces gars est que vous obtenez filetage sans avoir à se soucier trop de l'endroit où vous êtes fil est l'exécution, ce qui est idéal pour les tâches simples.

avant d'utiliser un BackgroundWorker considérer d'abord si vous souhaitez annuler un thread (fermeture de l'application, annulation de l'utilisateur), alors vous devez décider si votre thread devrait vérifiez pour les annulations ou si elle doit être poussée à l'exécution elle-même.

BackgroundWorker.CancelAsync() réglera CancellationPending à true mais ne fera plus rien, il est alors de la responsabilité des threads de vérifier en permanence cela, gardez à l'esprit également que vous pourriez finir avec une condition de course dans cette approche où votre Utilisateur a annulé, mais le thread terminé avant les tests pour CancellationPending .

Thread.Abort() d'autre part lancera un exception dans l'exécution thread qui impose l'annulation de ce thread, vous devez faire attention à ce qui pourrait être dangereux si cette exception était soudainement soulevée dans l'exécution cependant.

"151960920 Threading" besoins d'un examen très attentif quelle que soit la tâche, pour certains plus de la lecture:

programmation parallèle dans le cadre. net Géré Filetage Meilleures Pratiques

8
répondu Brett Ryan 2011-04-21 10:27:59

j'ai su utiliser les threads avant de savoir.net, donc il a fallu que je m'habitue quand j'ai commencé à utiliser BackgroundWorkers. Matt Davis a résumé la différence avec beaucoup d'excellence, mais j'ajouterais qu'il est plus difficile de comprendre exactement ce que le code fait, et cela peut rendre le débogage plus difficile. Il est plus facile de penser à créer et fermer des fils, IMO, que de penser à donner du travail à un pool de fils.

Je ne peux toujours pas faire de commentaire poteaux d'autres personnes, ainsi pardonnez mes lamentations momentanées en employant une réponse pour s'adresser aux jetées7

N'utilisez pas de fil.Abort (); au lieu de cela, signalez un événement et concevez votre thread pour qu'il se termine avec élégance lorsqu'il est signalé. Fil.Abort() soulève une ThreadAbortException à un point arbitraire dans l'exécution du thread, qui peut faire toutes sortes de choses malheureuses comme les moniteurs orphelins, l'état partagé corrompu, et ainsi de suite. http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx

4
répondu ajs410 2009-10-28 20:31:29

si elle n'est pas cassée, réparez - la jusqu'à ce qu'elle le soit...c'est juste une blague :)

mais sérieusement BackgroundWorker est probablement très similaire à ce que vous avez déjà, si vous aviez commencé avec elle dès le début peut - être que vous auriez gagné un peu de temps-mais à ce point je ne vois pas le besoin. Sauf si quelque chose ne fonctionne pas, ou si vous pensez que votre code actuel est difficile à comprendre, alors je m'en tiendrais à ce que vous avez.

2
répondu Gandalf 2009-10-01 22:34:08

la différence fondamentale est, comme vous l'avez dit, de générer des événements GUI à partir du BackgroundWorker . Si le thread n'a pas besoin de mettre à jour l'affichage ou de générer des événements pour le thread GUI principal, alors il peut s'agir d'un thread simple.

2
répondu David R Tribble 2009-10-01 23:09:51

un travailleur d'arrière-plan est une classe qui fonctionne dans un thread séparé, mais il fournit des fonctionnalités supplémentaires que vous ne recevez pas avec un simple Thread (comme la gestion des rapports d'avancement des tâches).

si vous n'avez pas besoin des caractéristiques supplémentaires données par un travailleur d'arrière - plan - et il semble que vous n'en avez pas besoin-alors un fil serait plus approprié.

1
répondu Cesar 2009-10-01 22:34:57

je tiens à souligner un comportement de la classe des travailleurs de fond qui n'a pas encore été mentionné. Vous pouvez créer un Thread normal à exécuter en arrière-plan en définissant le Thread.IsBackground de la propriété.

les fils D'arrière-plan sont identiques aux fils d'avant-plan, sauf que les fils d'arrière-plan n'empêchent pas un processus de se terminer. [ 1 ]

vous pouvez tester ce behavoir en appelant la méthode suivante dans le constructeur de votre fenêtre de formulaire.

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = false; // <--- This will make the thread run in background
    thread.IsBackground = true; // <--- This will delay program termination

    thread.Start();
}

lorsque la propriété IsBackground est définie à true et que vous fermez la fenêtre, alors votre application se terminera normalement.

mais quand la propriété IsBackground est définie à false (par défaut) et que vous fermez la fenêtre, alors juste la fenêtre se désactivera mais le processus continuera à fonctionner.

la classe BackgroundWorker utilise un Thread qui tourne à l'arrière-plan.

1
répondu Doomjunky 2017-07-11 14:05:34

ce qui me rend perplexe, c'est que le concepteur de studio visuel ne vous permet d'utiliser que des travailleurs de fond et des minuteries qui ne fonctionnent pas réellement avec le projet de service.

il vous donne des commandes Drag et drop soignées sur votre service mais... n'essayez même pas de le déployer. Ne fonctionne pas.

Services: Utilisez seulement le système.Minuterie.Minuterie Système.Windows.Forme.Le minuteur ne fonctionnera pas même s'il est disponible dans la boîte à outils

Service: BackgroundWorkers ne fonctionnera pas quand il fonctionne comme un service L'Utilisation Du Système.Le filetage.ThreadPools au lieu ou d'appels Asynchrones

0
répondu scottweeden 2017-11-17 03:29:31