web-dev-qa-db-fra.com

Exécutez le processus d'arrière-plan dans Python et n'attendez PAS

Mon objectif est simple: lancer rsync et NE PAS ATTENDRE.

Python 2.7.9 sur Debian

Exemple de code:

rsync_cmd = "/usr/bin/rsync -a -e 'ssh -i /home/myuser/.ssh/id_rsa' {0}@{1}:'{2}' {3}".format(remote_user, remote_server, file1, file1)
rsync_cmd2 = "/usr/bin/rsync -a -e 'ssh -i /home/myuser/.ssh/id_rsa' {0}@{1}:'{2}' {3} &".format(remote_user, remote_server, file1, file1)
rsync_path = "/usr/bin/rsync"
rsync_args = shlex.split("-a -e 'ssh -i /home/mysuser/.ssh/id_rsa' {0}@{1}:'{2}' {3}".format(remote_user, remote_server, file1, file1))
#subprocess.call(rsync_cmd, Shell=True)     # This isn't supposed to work but I tried it
#subprocess.Popen(rsync_cmd, Shell=True)    # This is supposed to be the solution but not for me
#subprocess.Popen(rsync_cmd2, Shell=True)   # Adding my own Shell "&" to background it, still fails
#subprocess.Popen(rsync_cmd, Shell=True, stdin=None, stdout=None, stderr=None, close_fds=True)  # This doesn't work
#subprocess.Popen(shlex.split(rsync_cmd))   # This doesn't work
#os.execv(rsync_path, rsync_args)           # This doesn't work
#os.spawnv(os.P_NOWAIT, rsync_path, rsync_args) # This doesn't work
#os.system(rsync_cmd2)                      # This doesn't work
print "DONE"

(J'ai commenté les commandes d'exécution uniquement parce que je garde en fait tous mes essais dans mon code afin de savoir ce que j'ai fait et ce que je n'ai pas fait. Évidemment, je lancerais le script avec le droit ligne non commentée.)

Ce qui se passe est ceci ... Je peux regarder le transfert sur le serveur et quand c'est fini, alors je reçois un "DONE" imprimé à l'écran.

Ce que j'aimerais avoir, c'est un "DONE" imprimé immédiatement après l'émission de la commande rsync et pour que le transfert démarre.

Semble très simple. J'ai suivi les détails décrits dans d'autres articles, comme this one et this one, mais quelque chose l'empêche de fonctionner pour moi.

Merci d'avance.

(J'ai essayé tout ce que je peux trouver dans StackExchange et je n'ai pas l'impression qu'il s'agit d'un doublon car je n'arrive toujours pas à le faire fonctionner. Quelque chose ne va pas dans ma configuration et j'ai besoin d'aide.)

9
harperville

Voici un exemple vérifié pour Python REPL:

>>> import subprocess
>>> import sys
>>> p = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(100)'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT); print('finished')
finished

Comment vérifier cela via une autre fenêtre de terminal:

$ ps aux | grep python

Production:

user           32820   0.0  0.0  2447684   3972 s003  S+   10:11PM   0:00.01 /Users/user/venv/bin/python -c import time; time.sleep(100)
16
Viach Kakovskyi

Popen() démarre un processus enfant — il n'attend pas qu'il se termine. Vous devez appeler la méthode .wait() explicitement si vous voulez attendre le processus enfant. En ce sens, tous les sous-processus sont des processus d'arrière-plan.

D'autre part, le processus enfant peut hériter de diverses propriétés/ressources du parent telles que les descripteurs de fichiers ouverts, le groupe de processus, son terminal de contrôle, une configuration de signal, etc. - il peut conduire à empêcher les processus des ancêtres de quitter, par exemple sous-processus Python .check_call vs .check_output ou l'enfant peut mourir prématurément sur Ctrl-C (le signal SIGINT est envoyé au groupe de processus de premier plan) ou si la session de terminal est fermée (SIGHUP).

Pour dissocier complètement le processus enfant, vous devez en faire un démon . Parfois, quelque chose entre les deux pourrait être suffisant, par exemple, il suffit de rediriger la sortie héritée chez un petit-enfant pour que .communicate() dans le parent revienne lorsque son enfant immédiat se termine .

8
jfs