2014-12-23 7 views
11

ho voluto avviare un processo dal mio script python (main.py), in particolare voglio eseguire il comando di seguitoavviare un processo completamente indipendente

`nohup python ./myfile.py &` 

e questo file myfile.py dovrebbe anche dopo le mie principali uscite script Python.

Inoltre desidero ottenere il pid del nuovo processo.

ho provato os.spawnl*, os.exec* & subprocess.Popen metodi, tutti sono concludano mia myfile.py se il mio script main.py esce.

Mi può mancare qualcosa.

Aggiornamento: Posso utilizzare os.startfile con xdg-open? È un approccio corretto?

Esempio

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

Se controllo ps aux | grep long_process, non ho potuto vedere alcun processo in esecuzione.

long_process.py che continua a stampare del testo: nessuna uscita.

Sto facendo qualcosa di sbagliato qui?

+0

Puoi pubblicare un esempio minimo che non funziona? Dopo un sottoprocesso di importazione banale 'python -c '; subprocess.Popen (["sleep", "60"]) "l'output di' ps' mostra che "sleep" continua a funzionare bene dopo che Python è uscito. – user4815162342

+0

Stai eseguendo Python con un singolo argomento, '" nohup/usr/bin/python25 ... "', che non può funzionare perché l'eseguibile 'python' cercherà uno script in un file chiamato esattamente' nohup/usr/bin/... ', che non esiste. E dato che si specifica 'stderr' come' PIPE' senza mai leggere il contenuto della pipe, non si arriva mai a vedere il messaggio di errore. Perdere il 'nohup' e' & ', e semplicemente eseguire' subprocess.Popen ([sys.executable, "/.../ long_process.py"]) '. Inoltre, non specificare 'stdin' e' stderr' come pipe, a meno che non lo intendi. – user4815162342

+0

'nohup' ha più senso quando si avvia un processo da una shell. Non vedo 'shell = True' nella tua chiamata' Popen'. – 9000

risposta

10

Si apre il processo di lunga durata e mantenere un tubo ad esso. Quindi ti aspetti di parlarci. Quando lo script di avvio termina, non puoi più parlarne. Il processo di lunga durata riceve uno SIGPIPE ed esce.

Quanto segue ha funzionato per me (Linux, Python 2.7).

Creare una lunga durata eseguibile:

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

Run 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 

Uscire dal REPL e vedere il processo ancora in corso:

>>> ^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 

Se si desidera prima comunicare al processo avviato e poi lasciarlo da solo per eseguire ulteriormente, hai alcune opzioni:

  • Maniglia SIGPIPE nel tuo lungo processo, non morire su di esso. In diretta senza stdin dopo l'uscita del processo di avvio.
  • Passa tutto ciò che desideri utilizzando argomenti, ambiente o un file temporaneo.
  • Se si desidera una comunicazione bidirezionale, considerare l'utilizzo di una pipe denominata (man mkfifo) o di un socket o di scrivere un server appropriato.
  • Rende il fork del processo di lunga durata dopo che è stata eseguita la fase iniziale di comunicazione bidirezionale.
+0

Ottima risposta, è un buon punto che il processo muoia a causa di 'SIGPIPE'. (Nel codice della domanda il processo non è mai iniziato, ma l'OP potrebbe aver provato anche altre varianti che sono state avviate e morte a causa di 'SIGPIPE'.) – user4815162342

+0

Non crea" un processo completamente indipendente "(che cosa' python -daemon' fa). Inoltre, [un processo figlio non otterrà SIGPIPE in Python 2] (http://stackoverflow.com/a/22083141/4279). Anche se in casi semplici, la soluzione è sufficiente (dovresti reindirizzare a 'os.devnull' child stdin/stdout/stderr per evitare di attendere input e/o output spuri al terminale). – jfs

+0

@ user4815162342: Non morirà a causa di SIGPIPE in Python 2 (la domanda ha tag [tag: python2.7]). – jfs

5

È possibile utilizzare os.fork().

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

Funziona +1, tuttavia Popen è molto comodo. – Garfield

3

non ho potuto vedere alcun processo in esecuzione.

Non si vede alcun processo in esecuzione perché il processo figlio python termina immediatamente. Gli argomenti Popen non sono corretti come @user4815162342 says in the comment.

di lanciare una completamente indipendente processo , è necessario utilizzare python-daemon package:

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

with daemon.DaemonContext(): 
    main() 

Anche se potrebbe essere sufficiente nel tuo caso, per avviare il bambino con corretti Popen argomenti:

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) 

Se il processo figlio non richiede python2.5, è possibile utilizzare invece sys.executable (per utilizzare la stessa versione Python del genitore).

Nota: il codice chiude DEVNULL nel genitore senza attendere che il processo figlio termini (non ha alcun effetto sul figlio).