2012-03-26 6 views
5

Ho uno script SGE per eseguire un codice Python, inviato alla coda usando qsub. Nello script python, ho alcune istruzioni di stampa (aggiornandomi sullo stato di avanzamento del programma). Quando eseguo lo script python dalla riga di comando, le istruzioni di stampa vengono inviate allo stdout. Per lo script sge, utilizzo l'opzione -o per reindirizzare l'output su un file. Tuttavia, sembra che lo script li invierà al file solo dopo che lo script Python ha completato l'esecuzione. Ciò è fastidioso perché (a) non riesco più a visualizzare gli aggiornamenti in tempo reale sul programma e (b) se il mio lavoro non termina correttamente (ad esempio se il mio lavoro viene espulso dalla coda) nessuno degli aggiornamenti viene stampato. Come posso assicurarmi che lo script stia scrivendo sul file ogni volta che voglio stampare qualcosa, invece di rimetterlo insieme alla fine?Script SGE: stampa su file durante l'esecuzione (non solo alla fine)?

risposta

5

Penso che si stia verificando un problema con l'output bufferizzato. Python usa una libreria per gestire il suo output e la libreria sa che è più efficiente scrivere un blocco in un momento in cui non sta parlando con un tty.

Ci sono un paio di modi per ovviare a questo problema. È possibile eseguire python con l'opzione "-u" (vedi la pagina man pitone per i dettagli), per esempio, con qualcosa di simile come la prima linea del vostro script:

#! /usr/bin/python -u 

ma questo non funziona se stai usando il trucco "/ usr/bin/env" perché non sai dove è installato python.

Un altro modo è quello di riaprire lo stdout con qualcosa di simile:

import sys 
import os 

# reopen stdout file descriptor with write mode 
# and 0 as the buffer size (unbuffered) 
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 

Nota il parametro bufsize di os.fdopen essere impostato a 0 per costringerlo ad essere senza buffer. Puoi fare qualcosa di simile con sys.stderr.

+0

Grazie! Non sapevo che questo avesse qualcosa a che fare con Python. Anche trovato questo post utile http://stackoverflow.com/questions/107705/python-output-buffering – miz

3

Ho appena riscontrato un problema simile con SGE e nessun suggested method in "unbuffer" il file IO sembrava funzionare per me. Ho dovuto aspettare fino alla fine dell'esecuzione del programma per vedere qualsiasi output.

La soluzione che ho trovato era di avvolgere sys.stdout in un oggetto personalizzato che reimplementa il metodo "write". Invece di scrivere effettivamente su stdout, questo nuovo metodo apre invece il file in cui viene reindirizzato IO, aggiunge i dati desiderati e quindi chiude il file. È un po 'brutto, ma ho trovato risolto il problema, poiché l'effettiva apertura/chiusura del file costringe l'IO ad essere interattivo.

Ecco un esempio minimo:

import os, sys, time 

class RedirIOStream: 
    def __init__(self, stream, REDIRPATH): 
    self.stream = stream 
    self.path = REDIRPATH 
    def write(self, data): 
    # instead of actually writing, just append to file directly! 
    myfile = open(self.path, 'a') 
    myfile.write(data) 
    myfile.close() 
    def __getattr__(self, attr): 
    return getattr(self.stream, attr) 


if not sys.stdout.isatty(): 
    # Detect redirected stdout and std error file locations! 
    # Warning: this will only work on LINUX machines 
    STDOUTPATH = os.readlink('/proc/%d/fd/1' % os.getpid()) 
    STDERRPATH = os.readlink('/proc/%d/fd/2' % os.getpid()) 
    sys.stdout=RedirIOStream(sys.stdout, STDOUTPATH) 
    sys.stderr=RedirIOStream(sys.stderr, STDERRPATH) 


# Simple program to print msg every 3 seconds 
def main():  
    tstart = time.time() 
    for x in xrange(10): 
    time.sleep(3) 
    MSG = ' %d/%d after %.0f sec' % (x, args.nMsg, time.time()-tstart) 
    print MSG 

if __name__ == '__main__': 
    main() 
3

Questo è SGE buffer l'output del processo, succede se il suo un processo di pitone o di qualsiasi altro.

In generale è possibile ridurre o disabilitare il buffering in SGE modificandolo e ricompilando. Ma non è una gran cosa da fare, tutti i dati verranno scritti lentamente sul disco e influenzeranno le tue prestazioni generali.

0

questo funziona per me:

class ForceIOStream: 
    def __init__(self, stream): 
     self.stream = stream 

    def write(self, data): 
     self.stream.write(data) 
     self.stream.flush() 
     if not self.stream.isatty(): 
      os.fsync(self.stream.fileno()) 

    def __getattr__(self, attr): 
     return getattr(self.stream, attr) 


sys.stdout = ForceIOStream(sys.stdout) 
sys.stderr = ForceIOStream(sys.stderr) 

e la questione ha a che fare con NFS non sincronizzazione dei dati al master fino a quando un file viene chiuso o fsync viene chiamato.

4

Come altri hanno accennato, è per motivi di prestazioni non sempre scrivere lo stdout quando non è collegato a un tty.

Se si dispone di un punto specifico in cui si desidera lo stdout da scrivere, è possibile forzare che utilizzando

import sys 
sys.stdout.flush() 

in quel punto.

0

Perché non stampare su un file anziché su stdout?

outFileID = open('output.log','w') 
print(outFileID,'INFO: still working!') 
print(outFileID,'WARNING: blah blah!') 

e utilizzare

tail -f output.log 
0

mi ha colpito questo stesso problema di oggi e risolto il programma semplicemente con la scrittura su disco, invece di stampa:

with open('log-file.txt','w') as out: 
    out.write(status_report) 
Problemi correlati