2010-05-21 9 views
7

Sto lavorando con un sistema cluster su linux (www.mosix.org) che mi consente di eseguire i lavori e farli funzionare su computer diversi. I lavori vengono eseguiti in questo modo:Come dire id processo in Python

mosrun ls & 

Questo, naturalmente, creare il processo ed eseguirlo sullo sfondo, restituendo l'ID di processo, in questo modo:

[1] 29199 

Più tardi si tornerà. Sto scrivendo un'infrastruttura Python che esegue i lavori e li controlla. Per questo voglio eseguire i lavori usando il programma mosrun come sopra, e salvare l'ID del processo generato (29199 in questo caso). Questo naturalmente non può essere fatto usando os.system o commands.getoutput, in quanto l'ID stampato non è ciò che il processo stampa in uscita ... Eventuali indizi?

Edit:

Poiché lo script python serve solo per eseguire inizialmente lo script, gli script hanno bisogno di correre più a lungo rispetto alla shell Python. Immagino che significhi che il processo mosrun non può essere il processo secondario della sceneggiatura. Eventuali suggerimenti?

Grazie

+0

Normalmente i processi figlio continuano a essere eseguiti quando il processo padre muore. –

risposta

2

Sembra che si desideri garantire che il processo figlio sia daemonized - PEP 3143, a cui sto puntando, documenti e punti a un'implementazione di riferimento per questo e punta anche ad altri.

Una volta che il processo (ancora in esecuzione codice Python) è daemonized, sia esso con i mezzi offerti nel PEP 3143 o altri, è possibile os.execl (o altro os.exec... funzione) il codice di destinazione - questo viene eseguito detto codice di destinazione in esattamente lo stesso processo che abbiamo appena detto è demonizzato, e quindi continua a essere demonizzato, come desiderato.

L'ultimo passo non può usare subprocess perché ha bisogno per funzionare in stesso (daemonized) processo, sovrapponendo il suo codice eseguibile - esattamente ciò che os.execl e gli amici sono per.

Il primo passo, prima di daemonization, potrebbe in teoria essere fatto tramite subprocess, ma questo è un po 'scomodo (è necessario mettere il codice demonizzare-then-os.exec in un separato .py): più comunemente che ci si vuole solo os.fork e demoni immediatamente il processo figlio.

subprocess è molto conveniente come metodo per la maggior parte multipiattaforma per eseguire altri processi, ma non può davvero sostituire il buon vecchio approccio "fork ed exec" di Unix per usi avanzati (come la demonizzazione, in questo caso) - - ed è per questo che è una buona cosa che la libreria standard di Python ti permetta anche di farlo tramite queste funzioni nel modulo os! -)

+0

Grazie. E sarò in grado di conoscere l'ID di processo del processo demonizzato dal vecchio processo? –

+0

La doppia forcella ha un po 'di ritardo, quindi è necessario comunicarla - ad esempio, il processo figlio potrebbe scrivere l'id del processo del nipote sul suo 'stdout' (da cui il processo padre può ottenerlo) subito dopo biforcuta e prima che termini. Tuttavia, è necessario elaborare il proprio protocollo, poiché non esiste uno stabilito nella libreria standard di Python. –

3

Utilizzare subprocess modulo. Le istanze Popen hanno un attributo pid.

+0

Eccellente: cercavo anche questo – wvd

+0

Non significa che il mio nuovo processo sarà figlio del processo Python? cosa succederà quando avrò terminato il processo Python? (vedi modifica). Grazie –

0

Grazie a tutti per l'aiuto. Ecco cosa ho fatto alla fine e sembra funzionare bene. Il codice utilizza python-daemon. Forse dovrebbe essere fatto qualcosa di più intelligente sul trasferimento dell'id del processo dal figlio al padre, ma questa è la parte più facile.

import daemon 
def run_in_background(command, tmp_dir="/tmp"): 

    # Decide on a temp file beforehand 
    warnings.filterwarnings("ignore", "tempnam is a potential security") 
    tmp_filename = os.tempnam(tmp_dir) 

    # Duplicate the process 
    pid = os.fork() 


    # If we're child, daemonize and run 
    if pid == 0: 
     with daemon.DaemonContext(): 
      child_id = os.getpid() 
      file(tmp_filename,'w').write(str(child_id)) 
      sp = command.split(' ') 
      os.execl(*([sp[0]]+sp)) 
    else: 
     # If we're a parent, poll for the new file 
     n_iter = 0 
     while True: 
      if os.path.exists(tmp_filename): 
       child_id = int(file(tmp_filename, 'r').read().strip()) 
       break 

      if n_iter == 100: 
       raise Exception("Cannot read process id from temp file %s" % tmp_filename) 
      n_iter += 1 

      time.sleep(0.1) 

     return child_id