Quelques astuces sur comment détacher le processus enfant du processus appelant (démarrer le processus enfant en arrière-plan).
Supposez que vous voulez démarrer une tâche longue à partir d'un script CGI. C'est-à-dire que le processus enfant doit vivre plus longtemps que le processus d'exécution du script CGI.
L'exemple classique de la documentation du module subprocess est le suivant :
import subprocess
import sys
# Du code ici
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Appeler le sous-processus
# Encore un peu de code ici
L'idée ici est que vous ne voulez pas attendre à la ligne 'Appeler le sous-processus' jusqu'à ce que longtask.py ait terminé. Mais il n'est pas clair ce qu'il se passe après la ligne 'encore un peu de code ici' de l'exemple.
Ma plateforme cible était FreeBSD, mais le développement était sur Windows, donc j'ai rencontré le problème sur Windows en premier.
Sous Windows (Windows XP), le processus parent ne se terminera pas tant que longtask.py n'aura pas terminé son travail. Ce n'est pas ce que vous voulez dans un script CGI. Le problème n'est pas spécifique à Python ; dans la communauté PHP, les problèmes sont les mêmes.
La solution est de passer le drapeau de création de processus DETACHED_PROCESS Process Creation Flag à la fonction sous-jacente CreateProcess dans l'API Windows. Si vous avez installé pywin32, vous pouvez importer le drapeau depuis le module win32process, sinon vous devez le définir vous-même :
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/* UPD 2015.10.27 @eryksun dans un commentaire ci-dessous note que le drapeau sémantiquement correct est CREATE_NEW_CONSOLE (0x00000010) */
Sous FreeBSD, nous avons un autre problème : lorsque le processus parent se termine, il termine également les processus enfants. Et ce n'est pas ce que vous voulez dans un script CGI non plus. Quelques expériences ont montré que le problème semblait être lié au partage de sys.stdout. Et la solution de travail était la suivante :
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Je n'ai pas vérifié le code sur d'autres plateformes et je ne connais pas les raisons du comportement sous FreeBSD. Si quelqu'un sait, veuillez partager vos idées. Une recherche sur le démarrage de processus en arrière-plan en Python ne semble pas encore éclairer.
0 votes
Pour ceux qui recherchent un cours de Python gratuit et interactif, voici : theconstructsim.com/robotigniteacademy_learnros/…
0 votes
Je ne comprends pas, quel est le problème avec
import os; os.system('pip list | grep anatome')
? Au moins cela vous permet de faire du piping comme le montre mon exemple. Il n'est pas clair comment faire cela avecimport subprocess; subprocess.run(["ls", "-l"])
.