2012-03-26 11 views
5

Tengo un script SGE para ejecutar algún código python, enviado a la cola usando qsub. En el script de Python, tengo algunas declaraciones impresas (actualizándome sobre el progreso del programa). Cuando ejecuto el script de python desde la línea de comando, las instrucciones de impresión se envían a stdout. Para el script sge, uso la opción -o para redirigir el resultado a un archivo. Sin embargo, parece que el script solo los enviará al archivo una vez que el script de python haya completado la ejecución. Esto es molesto porque (a) ya no puedo ver actualizaciones en tiempo real en el programa y (b) si mi trabajo no finaliza correctamente (por ejemplo, si mi trabajo es expulsado de la cola) no se imprime ninguna de las actualizaciones. ¿Cómo puedo asegurarme de que el script está escribiendo en el archivo cada vez que quiero imprimir algo, en lugar de agruparlo al final?SGE script: imprimir en el archivo durante la ejecución (no solo al final)?

Respuesta

5

Creo que se encuentra con un problema con la salida de búfer. Python usa una biblioteca para manejar su salida, y la biblioteca sabe que es más eficiente escribir un bloque a la vez cuando no está hablando con un tty.

Hay un par de formas de evitar esto. Puede ejecutar Python con la opción "-u" (consulte la página del pitón para más detalles), por ejemplo, con algo como esto como la primera línea del script:

#! /usr/bin/python -u 

pero esto no funciona si está utilizando el truco "/ usr/bin/env" porque no sabe dónde está instalado Python.

Otra manera es volver a abrir la salida estándar con algo como esto:

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 el parámetro bufsize de os.fdopen se establece en 0 para forzarlo a estar sin búfer. Puedes hacer algo similar con sys.stderr.

+0

Gracias! No me di cuenta de que esto tenía algo que ver con Python. También encontré este post útil http://stackoverflow.com/questions/107705/python-output-buffering – miz

3

Acabo de encontrar un problema similar con SGE, y no suggested method para "liberar" el archivo IO parecía funcionar para mí. Tuve que esperar hasta el final de la ejecución del programa para ver cualquier salida.

La solución alternativa que encontré fue envolver sys.stdout en un objeto personalizado que implementa de nuevo el método de "escritura". En lugar de escribir en stdout, este nuevo método abre el archivo donde se redirige IO, lo agrega con los datos deseados y luego cierra el archivo. Es un poco feo, pero encontré que resolvió el problema, ya que la apertura/cierre real del archivo obliga a IO a ser interactivo.

Aquí está un ejemplo mínimo:

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

Esto se SGE amortiguar la salida de su proceso, que sucede si es un proceso de pitón o cualquier otro.

En general, puede disminuir o desactivar el almacenamiento en memoria intermedia en SGE, cambiándolo y volviendo a compilar. Pero no es una gran cosa que hacer, todos esos datos se escribirán lentamente en el disco y afectarán su rendimiento general.

0

Esto funciona para mí:

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) 

y la cuestión tiene que ver con NFS no sincronizar datos de nuevo al maestro hasta un archivo está cerrado o fsync se llama.

4

Como han mencionado otros, es por razones de rendimiento no escribir siempre la salida estándar cuando no está conectada a un tty.

Si usted tiene un punto específico en el que desea que la salida estándar a ser escrito, puede forzar a que mediante el uso

import sys 
sys.stdout.flush() 

en ese punto.

0

¿Por qué no imprimir en un archivo en lugar de stdout?

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

y utilizar

tail -f output.log 
0

llegué a este mismo problema hoy y lo resolvió con sólo escribir en el disco en lugar de imprimir:

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