web-dev-qa-db-fra.com

Lancer un processus complètement indépendant

Je voulais lancer un processus à partir de mon python (main.py), en particulier, je veux exécuter la commande ci-dessous

`Nohup python ./myfile.py &`

et ce fichier myfile.py devrait même après la sortie de mon script principal python.

De plus, je souhaite obtenir le pid du nouveau processus.

J'ai essayé os.spawnl*, os.exec* & subprocess.Popen méthodes, toutes mettent fin à mon myfile.py si mon script main.py se termine.

Il me manque peut-être quelque chose.

Mise à jour: puis-je utiliser os.startfile avec xdg-open? Est-ce une bonne approche?

Exemple

a = subprocess.Popen([sys.executable, "Nohup /usr/bin/python25 /long_process.py &"],\
     stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
print a.pid

Si je vérifie ps aux | grep long_process, Je n'ai vu aucun processus en cours d'exécution.

long_process.py qui continue d'imprimer du texte: pas de sortie.

Suis-je en train de faire quelque chose de mal ici?

16
Garfield

Vous ouvrez votre processus de longue durée et gardez un tuyau vers lui . Vous vous attendez donc à lui en parler. Lorsque votre script de lanceur se termine, vous ne pouvez plus lui parler. Le processus de longue durée reçoit un SIGPIPE et se termine.

Ce qui suit vient de fonctionner pour moi (Linux, Python 2.7).

Créez un exécutable de longue durée:

$ echo "sleep 100" > ~/tmp/sleeper.sh

Exécutez Python REPL:

$ python
>>>

import subprocess
import os
p = subprocess.Popen(['/bin/sh', os.path.expanduser('~/tmp/sleeper.sh')])
# look ma, no pipes!
print p.pid
# prints 29893

Quittez le REPL et voyez le processus toujours en cours:

>>> ^D
$ ps ax | grep sleeper
29893 pts/0    S      0:00 /bin/sh .../tmp/sleeper.sh
29917 pts/0    S+     0:00 grep --color=auto sleeper

Si vous souhaitez d'abord communiquer avec le processus démarré puis le laisser tranquille pour continuer, vous avez quelques options:

  • Gérez SIGPIPE dans votre processus de longue haleine, ne mourez pas dessus. Vivez sans stdin après la fin du processus du lanceur.
  • Passez tout ce que vous vouliez en utilisant des arguments, un environnement ou un fichier temporaire.
  • Si vous souhaitez une communication bidirectionnelle, pensez à utiliser un canal nommé ( man mkfifo ) ou une socket, ou à écrire un serveur approprié.
  • Faites en sorte que le processus de longue durée se termine après la phase de communication bidirectionnelle initiale.
13
9000

Vous pouvez utiliser os.fork().

import os
pid=os.fork()
if pid==0: # new process
    os.system("Nohup python ./myfile.py &")
    exit()
# parent process continues
7
Hannes Karppila

Je ne pouvais voir aucun processus en cours d'exécution.

Aucun processus n'est en cours d'exécution car le processus enfant python se ferme immédiatement. Les arguments Popen sont incorrects car l'utilisateur4815162342 dit dans le commentaire .

Pour lancer un processus complètement indépendant , vous pouvez utiliser python-daemon package ou utilisez systemd/supervisord/etc:

#!/usr/bin/python25
import daemon
from long_process import main

with daemon.DaemonContext():
    main()

Bien que cela puisse suffire dans votre cas, pour démarrer l'enfant avec les arguments Popen corrects:

with open(os.devnull, 'r+b', 0) as DEVNULL:
    p = Popen(['/usr/bin/python25', '/path/to/long_process.py'],
              stdin=DEVNULL, stdout=DEVNULL, stderr=STDOUT, close_fds=True)
time.sleep(1) # give it a second to launch
if p.poll(): # the process already finished and it has nonzero exit code
    sys.exit(p.returncode)

Si le processus enfant ne nécessite pas python2.5 alors vous pouvez utiliser sys.executable à la place (pour utiliser la même version Python version que le parent).

Remarque: le code ferme DEVNULL dans le parent sans attendre la fin du processus enfant (il n'a aucun effet sur l'enfant).

6
jfs