J'ai une question stylistique 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 BackgroundWorker
un formulaire sur une (while(true))
boucle infinie . Dans cette boucle, j'utilise WaitHandle.WaitAny
pour garder le thread en sommeil jusqu'à ce que quelque chose d'intéressant se produise. Un des descripteurs d'événements sur StopThread
lesquels j'attends est un événement " " pour que je puisse sortir de la boucle. Cet événement est signalé lors de mon dépassement Form.Dispose()
.
J'ai lu quelque part qui BackgroundWorker
est vraiment destiné aux opérations avec lesquelles vous ne voulez pas lier l'interface utilisateur et qui ont une fin finie - comme le téléchargement d'un fichier ou le traitement d'une séquence d'éléments. Dans ce cas, la "fin" est inconnue et uniquement lorsque la fenêtre est fermée. Par conséquent, serait-il plus approprié pour moi d'utiliser un thread d'arrière-plan plutôt que BackgroundWorker
dans ce but?
la source
CancelAsync
(et testezCancellationPending
si votre thread va interroger sur de courts intervalles, si vous voulez qu'une exception soit levée à la place, utilisez unSystem.Threading.Thread.Abort()
qui lève une exception dans le bloc de thread lui-même, choisissez le bon modèle pour la situation.Certaines de mes pensées ...
la source
BackgroundWorker
est conçu pour signaler la progression du thread à une partie intéressée, ce qui implique généralement une interface utilisateur. La documentation MSDN pour la classe le rend très clair. Si vous avez simplement besoin d'une tâche à effectuer en arrière-plan, préférez utiliser unThreadPool
thread.System.Windows.Forms
assemblée;BackgroundWorker
est également utile pour les applications WPF et ces applications peuvent ne pas avoir de référence à WinForms.À peu près ce que Matt Davis a dit, avec les points supplémentaires suivants:
Pour moi, le principal différenciateur
BackgroundWorker
est le classement automatique de l'événement terminé via leSynchronizationContext
. Dans un contexte d'interface utilisateur, cela signifie que l'événement terminé se déclenche 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 leBackgroundWorker
dans un contexte d'interface utilisateur.Les tâches exécutées via le
ThreadPool
ne peuvent pas être facilement annulées (cela inclutThreadPool
.QueueUserWorkItem
Et les délégués s'exécutent de manière asyncronale). Ainsi, même si cela évite la surcharge de la rotation des threads, si vous avez besoin d'une annulation, utilisez un threadBackgroundWorker
ou (plus probablement en dehors de l'interface utilisateur) faites tourner un thread et gardez une référence à celui-ci afin que vous puissiez l'appelerAbort()
.la source
De plus, vous liez un thread de pool de threads pour la durée de vie du travailleur d'arrière-plan, ce qui peut être préoccupant car il n'y en a qu'un nombre fini. Je dirais que si vous ne créez le fil qu'une seule fois pour votre application (et n'utilisez aucune des fonctionnalités du travailleur d'arrière-plan), utilisez un fil de discussion plutôt qu'un fil d'arrière-plan / threadpool.
la source
Vous savez, il est parfois plus simple de travailler avec un BackgroundWorker, que vous utilisiez Windows Forms, WPF ou toute autre technologie. La partie intéressante de ces types est que vous obtenez des threads sans avoir à vous soucier trop de l'endroit où vous exécutez les threads, ce qui est idéal pour les tâches simples.
Avant d'utiliser un
BackgroundWorker
considérez d'abord si vous souhaitez annuler un thread (fermeture de l'application, annulation de l'utilisateur), vous devez décider si votre thread doit vérifier les annulations ou s'il doit être poussé sur l'exécution elle-même.BackgroundWorker.CancelAsync()
se mettraCancellationPending
àtrue
mais ne fera rien de plus, c'est alors la responsabilité des threads de vérifier continuellement cela, gardez à l'esprit également que vous pourriez vous retrouver avec une condition de concurrence dans cette approche où votre utilisateur a annulé, mais le thread s'est terminé avant de tester pourCancellationPending
.Thread.Abort()
d'un autre côté lèvera une exception dans l'exécution du thread qui impose l'annulation de ce thread, vous devez cependant faire attention à ce qui pourrait être dangereux si cette exception était soudainement levée pendant l'exécution.Le threading nécessite un examen très attentif, quelle que soit la tâche, pour une lecture plus approfondie:
Programmation parallèle dans le .NET Framework Managed Threading Meilleures pratiques
la source
Je savais comment utiliser les threads avant de connaître .NET, il a donc fallu un certain temps pour m'y habituer lorsque j'ai commencé à utiliser
BackgroundWorker
s. Matt Davis a résumé la différence avec une grande excellence, mais j'ajouterais qu'il est plus difficile de comprendre exactement ce que fait le code, et cela peut rendre le débogage plus difficile. Il est plus facile de penser à créer et à fermer des threads, IMO, que de penser à donner du travail à un pool de threads.Je ne peux toujours pas commenter les messages des autres, alors pardonnez ma boiterie momentanée en utilisant une réponse pour aborder les piers7
Ne l'utilisez pas à la
Thread.Abort();
place, signalez un événement et concevez votre thread pour qu'il se termine correctement lorsqu'il vous est signalé.Thread.Abort()
lève unThreadAbortException
à un moment arbitraire de l'exécution du thread, ce qui peut faire toutes sortes de choses malheureuses comme des moniteurs orphelins, un état partagé corrompu, etc.http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx
la source
Si ce n'est pas cassé - réparez-le jusqu'à ce que ce soit ... je plaisante :)
Mais sérieusement, BackgroundWorker est probablement très similaire à ce que vous avez déjà, si vous l'aviez commencé depuis le début, vous auriez peut-être gagné du temps - mais à ce stade, je n'en vois pas le besoin. À moins que quelque chose ne fonctionne pas ou que vous pensiez que votre code actuel est difficile à comprendre, je m'en tiendrai à ce que vous avez.
la source
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 principal de l'interface graphique, il peut s'agir d'un simple thread.la source
Je veux souligner un comportement de la classe BackgroundWorker qui n'a pas encore été mentionné. Vous pouvez faire en sorte qu'un Thread normal s'exécute en arrière-plan en définissant la propriété Thread.IsBackground.
Vous pouvez tester ce comportement en appelant la méthode suivante dans le constructeur de votre fenêtre de formulaire.
Lorsque la propriété IsBackground est définie sur true et que vous fermez la fenêtre, votre application se terminera normalement.
Mais lorsque la propriété IsBackground est définie sur false (par défaut) et que vous fermez la fenêtre, alors seule la fenêtre disparaîtra mais le processus continuera à s'exécuter.
La classe BackgroundWorker utilise un thread qui s'exécute en arrière-plan.
la source
Un travailleur d'arrière-plan est une classe qui fonctionne dans un thread distinct, mais il fournit des fonctionnalités supplémentaires que vous n'obtenez pas avec un simple thread (comme la gestion du rapport de progression des tâches).
Si vous n'avez pas besoin des fonctionnalités supplémentaires fournies par un travailleur en arrière-plan - et il semble que vous n'en ayez pas besoin - alors un thread serait plus approprié.
la source
Ce qui me rend perplexe, c'est que le concepteur de studio visuel vous permet uniquement d'utiliser des BackgroundWorkers et des minuteries qui ne fonctionnent pas réellement avec le projet de service.
Il vous donne des commandes de glisser-déposer sur votre service, mais ... n'essayez même pas de le déployer. Ça ne marchera pas.
Services: utilisez uniquement System.Timers.Timer System.Windows.Forms.Timer ne fonctionnera pas même s'il est disponible dans la boîte à outils
Services: BackgroundWorkers ne fonctionnera pas lorsqu'il est exécuté en tant que service Utilisez plutôt System.Threading.ThreadPools ou les appels Async
la source