Explication des threads démons

237

Dans la documentation Python, il est dit:

Un thread peut être marqué comme "thread démon". La signification de cet indicateur est que le programme Python entier se ferme lorsqu'il ne reste que des threads démon. La valeur initiale est héritée du thread de création.

Quelqu'un at-il une explication plus claire de ce que cela signifie ou un exemple pratique montrant où vous définiriez les threads daemonic?

Clarifiez-le pour moi: donc la seule situation dans laquelle vous ne définiriez pas de threads daemonic, c'est quand vous voulez qu'ils continuent à fonctionner après la fin du thread principal?

Corey Goldberg
la source

Réponses:

448

Certains threads effectuent des tâches d'arrière-plan, comme l'envoi de paquets keepalive, ou l'exécution d'un ramasse-miettes périodique, ou autre. Celles-ci ne sont utiles que lorsque le programme principal est en cours d'exécution, et il est normal de les supprimer une fois que les autres threads, non démon, sont sortis.

Sans les threads démon, vous devez les suivre et leur dire de quitter avant que votre programme ne puisse complètement quitter. En les définissant en tant que threads démon, vous pouvez les laisser s'exécuter et les oublier, et lorsque votre programme se ferme, tous les threads démon sont automatiquement supprimés.

Chris Jester-Young
la source
1
Donc, si j'ai un thread enfant qui effectue une opération d'écriture de fichier définie sur non-démon, cela signifie-t-il que je dois le faire quitter explicitement?
Ciasto piekarz
8
@san Que fait votre thread d'écrivain une fois qu'il a fini d'écrire? Revient-il simplement? Si oui, cela suffit. Les threads démon sont généralement destinés aux éléments qui s'exécutent en boucle et ne se terminent pas d'eux-mêmes.
Chris Jester-Young
Il ne fait rien, ni ne retourne, son seul but d'effectuer une opération d'écriture de fichier
Ciasto piekarz
2
@san S'il tombe du bas de la fonction thread, il retourne implicitement.
Chris Jester-Young
Il retourne Nonedans ce cas, mais peu importe, la valeur de retour n'est pas utilisée.
Chris Jester-Young
30

Disons que vous créez une sorte de widget de tableau de bord. Dans ce cadre, vous souhaitez qu'il affiche le nombre de messages non lus dans votre boîte e-mail. Vous faites donc un petit fil qui va:

  1. Connectez-vous au serveur de messagerie et demandez combien de messages non lus vous avez.
  2. Signalez l'interface graphique avec le nombre mis à jour.
  3. Dormez un peu.

Lorsque votre widget démarre, il crée ce fil, le désigne comme un démon et le démarre. Parce que c'est un démon, vous n'avez pas à y penser; à la fermeture de votre widget, le thread s'arrêtera automatiquement.

John Fouhy
la source
18

D'autres affiches ont donné quelques exemples de situations dans lesquelles vous utiliseriez des threads démon. Ma recommandation, cependant, est de ne jamais les utiliser.

Ce n'est pas parce qu'ils ne sont pas utiles, mais parce qu'il y a de mauvais effets secondaires que vous pouvez ressentir si vous les utilisez. Les threads démon peuvent toujours s'exécuter après que le runtime Python a commencé à détruire les éléments du thread principal, provoquant des exceptions assez bizarres.

Plus d'infos ici:

https://joeshaw.org/python-daemon-threads-considered-harmful/

https://mail.python.org/pipermail/python-list/2005-F February/343697.html

À strictement parler, vous n'en avez jamais besoin, cela facilite simplement la mise en œuvre dans certains cas.

Joe Shaw
la source
Toujours ce problème avec python 3? Il n'y a aucune information claire concernant ces "exceptions bizarres" dans la documentation.
kheraud
5
Extrait du blog de Joe: "Mise à jour de juin 2015: il s'agit du bogue Python 1856. Il a été corrigé dans Python 3.2.1 et 3.3, mais le correctif n'a jamais été rétroporté vers 2.x. (Une tentative de rétroportage vers la branche 2.7 a provoqué un autre bogue et il a été abandonné.) Les threads démon peuvent être corrects en Python> = 3.2.1, mais ne le sont certainement pas dans les versions antérieures. "
clacke
Je voudrais partager ici mon expérience: j'ai eu une fonction générée plusieurs fois en tant que Thread. À l'intérieur, j'avais une instance de Python logginget je m'attendais à ce que, après avoir terminé le thread, tous les objets (descripteurs de fichiers pour chaque thread / fonction) soient détruits. À la fin de mon programme, j'ai vu de nombreuses sorties comme IOError: [Errno 24] Too many open files:. Avec lsof -p pid_of_program, j'ai découvert que les FD étaient ouverts, même si les Thread / Functions ont fini leur travail. Solution de contournement? Suppression du gestionnaire de journaux à la fin de la fonction. Alors les daemonicfils ne sont pas fiables ...
ivanleoncz
17

Une façon plus simple de penser à cela, peut-être: lorsque main revient, votre processus ne se fermera pas si des threads non-démon sont toujours en cours d'exécution.

Un petit conseil: un arrêt propre est facile de se tromper lorsque les threads et la synchronisation sont impliqués - si vous pouvez l'éviter, faites-le. Utilisez des threads démon autant que possible.

Jonathan
la source
13

Chris a déjà expliqué ce que sont les threads démon, alors parlons de l'utilisation pratique. De nombreuses implémentations de pool de threads utilisent des threads démon pour les travailleurs de tâches. Les travailleurs sont des threads qui exécutent des tâches à partir de la file d'attente des tâches.

Le travailleur doit continuer d'attendre indéfiniment les tâches dans la file d'attente des tâches car il ne sait pas quand une nouvelle tâche apparaîtra. Le thread qui attribue des tâches (disons le thread principal) ne sait que lorsque les tâches sont terminées. Le thread principal attend dans la file d'attente des tâches pour se vider, puis se ferme. Si les travailleurs sont des threads utilisateur, c'est-à-dire non-démon, le programme ne se terminera pas. Il continuera d'attendre ces travailleurs qui courent indéfiniment, même si les travailleurs ne font rien d'utile. Marquez les threads démon des travailleurs, et le thread principal se chargera de les tuer dès qu'il aura fini de gérer les tâches.

Amit
la source
4
Soyez prudent avec ça! Si un programme soumet une tâche importante (par exemple, mettre à jour un fichier "en arrière-plan") dans une file d'attente de tâches démon, il y a un risque que le programme se termine avant d'exécuter la tâche, ou pire, au milieu de la mise à jour de ce fichier.
Solomon Slow
10

Citant Chris: "... lorsque votre programme se ferme, tous les threads démon sont automatiquement supprimés.". Je pense que cela résume. Vous devez être prudent lorsque vous les utilisez car ils se terminent brusquement lorsque le programme principal s'exécute jusqu'à la fin.

Basse
la source
4

Lorsque votre deuxième thread n'est pas Daemon, le thread principal principal de votre application ne peut pas se fermer car ses critères de sortie sont liés à la sortie également des threads non Daemon. Les threads ne peuvent pas être tués de force en python, par conséquent, votre application devra vraiment attendre la fin du ou des threads non-démon. Si ce comportement n'est pas celui que vous souhaitez, définissez votre deuxième thread en tant que démon afin qu'il n'empêche pas votre application de se fermer.

truthadjustr
la source