419 votes

Lancement d'un processus en arrière-plan en python

J'essaie de porter un shell script vers la version python, beaucoup plus lisible. Le shell original script démarre plusieurs processus (utilitaires, moniteurs, etc.) en arrière-plan avec "&". Comment puis-je obtenir le même effet en python ? J'aimerais que ces processus ne meurent pas lorsque les scripts python se terminent. Je suis sûr que cela est lié d'une manière ou d'une autre au concept de démon, mais je n'ai pas trouvé comment le faire facilement.

2 votes

La question qui fait vraiment double emploi est Comment lancer et exécuter un script externe en arrière-plan ? . Santé ;)

1 votes

Salut Artem. Veuillez accepter La réponse de Dan parce que (1) plus de votes, (2) subprocess.Popen() est la nouvelle voie recommandée depuis 2010 (nous sommes en 2015 maintenant) et (3) le question dupliquée rediriger ici a aussi une réponse acceptée à propos de subprocess.Popen() . A la vôtre :-)

1 votes

@olibre En fait, la réponse devrait être subprocess.Popen("<command>") avec le fichier <command> conduit par un shebang approprié. Cela fonctionne parfaitement pour moi (Debian) avec des scripts bash et python, implicitement shell et survit à son processus parent. stdout va au même terminal que celui de ses parents. Cela fonctionne donc un peu comme & dans une coquille, ce qui était la demande de l'OP. Mais bon, toutes les questions s'avèrent très complexes alors qu'un petit test l'a montré en un rien de temps ;)

524voto

Dan Points 3429

Alors que jkp La solution de l'auteur fonctionne, mais la nouvelle façon de faire (et celle que recommande la documentation) est d'utiliser la méthode de l'utilisateur. subprocess module. Pour les commandes simples, il est équivalent, mais il offre plus d'options si vous voulez faire quelque chose de compliqué.

Exemple pour votre cas :

import subprocess
subprocess.Popen(["rm","-r","some.file"])

Cela devrait fonctionner rm -r somefile en arrière-plan. Mais méfiez-vous : subprocess.Popen() ne lance un processus en arrière-plan que si rien dans le script python ne dépend de la sortie de la commande en cours d'exécution,

Par exemple, la commande suivante pas fonctionnent en arrière-plan :

import subprocess
ls_output=subprocess.Popen(["ls", "-a"], stdout=subprocess.PIPE)

Voir la documentation ici .

21 votes

@Dan : Comment puis-je tuer le processus une fois qu'il tourne en arrière-plan ? Je veux l'exécuter pendant un certain temps (c'est un démon avec lequel j'interagis) et le tuer quand j'en ai fini avec lui. La documentation ne m'aide pas...

0 votes

@Juan : Si vous travaillez sur un système unix, vous pouvez utiliser la fonction kill commande. Vous pouvez également le tuer à partir du gestionnaire de tâches de Windows.

1 votes

Dan, mais n'ai-je pas besoin de connaître le PID pour cela ? Le moniteur d'activité/gestionnaire de tâches n'est pas une option (il doit être programmé).

106voto

jkp Points 20410

Si vous voulez que votre processus démarre en arrière-plan, vous pouvez soit utiliser system() et l'appeler de la même manière que votre shell script l'a fait, ou vous pouvez spawn il :

import os
os.spawnl(os.P_DETACH, 'some_long_running_command')

Voir le documentation ici . Note os.P_DETACH est spécifique à win32 : vous pouvez utiliser os.P_NOWAIT pour une meilleure portabilité.

......

9 votes

Remarque : vous devez spécifier le chemin complet de l'exécutable. Cette fonction n'utilise pas la variable PATH et la variante qui l'utilise n'est pas disponible sous Windows.

40 votes

Fait carrément planter Python pour moi.

36 votes

Os.P_DETACH a été remplacé par os.P_NOWAIT.

57voto

Eli Courtwright Points 53071

Vous voulez probablement cette réponse à la question StackOverflow "Comment appeler une commande externe en Python" : http://stackoverflow.com/questions/89228/how-to-call-external-command-in-python/92395#92395

L'approche la plus simple consiste à utiliser l'option os.system fonction, par exemple

import os
os.system("some_command &")

Fondamentalement, tout ce que vous passez à la fonction system sera exécutée de la même manière que si vous l'aviez passée au shell dans un script.

12 votes

À mon avis, les scripts python sont généralement écrits pour être multiplateformes et s'il existe une solution multiplateforme simple, il est préférable de s'y tenir. On ne sait jamais si l'on devra travailler avec une autre plateforme à l'avenir :) Ou si un autre homme voudra migrer votre script vers sa plateforme.

10 votes

Cette commande est synchrone (c'est-à-dire qu'elle attend toujours la fin du processus lancé).

0 votes

@d9k os.system n'est pas portable ?

42voto

f p Points 1667

J'ai trouvé ceci ici :

Sous Windows (win xp), le processus parent ne se terminera pas tant que le bouton longtask.py a terminé son travail. Ce n'est pas ce que vous voulez dans un CGI-script. Le problème n'est pas spécifique à Python, dans la communauté PHP les problèmes sont les mêmes.

La solution consiste à passer DETACHED_PROCESS à l'indicateur sous-jacent CreateProcess dans l'API Win. Si vous avez installé pywin32, vous pouvez importer l'indicateur du 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

9 votes

+1 pour avoir montré comment conserver l'identifiant du processus. Et si quelqu'un veut tuer le programme plus tard avec l'id de processus : stackoverflow.com/questions/17856928/

7 votes

Il semble que ce soit uniquement Windows

14voto

Vous devriez probablement commencer à étudier le module os pour forker différents threads (en ouvrant une session interactive et en demandant help(os)). Les fonctions pertinentes sont fork et n'importe laquelle des fonctions exec. Pour vous donner une idée de la façon de commencer, mettez quelque chose comme ceci dans une fonction qui effectue le fork (la fonction doit prendre une liste ou un tuple 'args' comme argument qui contient le nom du programme et ses paramètres ; vous pouvez également définir stdin, out et err pour le nouveau thread) :

try:
    pid = os.fork()
except OSError, e:
    ## some debug output
    sys.exit(1)
if pid == 0:
    ## eventually use os.putenv(..) to set environment variables
    ## os.execv strips of args[0] for the arguments
    os.execv(args[0], args)

2 votes

os.fork() est vraiment utile, mais il présente l'inconvénient notable de n'être disponible que sur *nix.

0 votes

Le seul problème avec os.fork est qu'il est spécifique à win32.

0 votes

Plus de détails sur cette approche : Création d'un démon à la manière de Python

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X