2012-03-26 5 views
5

Ich habe ein SGE-Skript, um etwas Python-Code auszuführen, der mit qsub an die Warteschlange übergeben wird. Im Python-Skript habe ich ein paar Druckanweisungen (aktualisiert mich über den Fortschritt des Programms). Wenn ich das Python-Skript über die Befehlszeile ausführe, werden die print-Anweisungen an stdout gesendet. Für das Skript sge verwende ich die Option -o, um die Ausgabe in eine Datei umzuleiten. Es scheint jedoch, dass das Skript diese nur an die Datei sendet, nachdem das Python-Skript vollständig ausgeführt wurde. Dies ist ärgerlich, weil (a) ich Echtzeit-Updates auf dem Programm nicht mehr sehen kann und (b) wenn mein Job nicht korrekt beendet wird (zum Beispiel wenn mein Job aus der Warteschlange geworfen wird), werden keine Updates gedruckt. Wie kann ich sicherstellen, dass das Skript jedes Mal, wenn ich etwas ausdrucken möchte, in die Datei schreibt, anstatt alles am Ende zusammenzufassen?SGE-Skript: während der Ausführung in Datei drucken (nicht nur am Ende)?

Antwort

5

Ich denke, dass Sie auf ein Problem mit gepufferter Ausgabe stoßen. Python verwendet eine Bibliothek, um seine Ausgabe zu verarbeiten, und die Bibliothek weiß, dass es effizienter ist, einen Block zu einem Zeitpunkt zu schreiben, wenn er nicht mit einem tty spricht.

Es gibt ein paar Möglichkeiten, um dies zu umgehen. Sie können Python mit der Option „-u“ (siehe Python man Seite für Details), zum Beispiel, mit so etwas wie dies als die erste Zeile des Skripts ausführen:

#! /usr/bin/python -u 

aber das funktioniert nicht, wenn Sie verwenden den Trick "/ usr/bin/env", weil Sie nicht wissen, wo Python installiert ist.

Eine andere Möglichkeit ist es, die stdout mit so etwas wie dies wieder zu öffnen:

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) 

Notiere die bufsize Parameter von os.fdopen auf 0 gesetzt wird, um es zu zwingen ungepufferte zu sein. Sie können etwas ähnliches mit sys.stderr tun.

+0

Dank! Wusste nicht, dass das etwas mit Python zu tun hatte. Auch fand dieser Beitrag hilfreich http://stackoverflow.com/questions/107705/python-output-buffering – miz

3

Ich stieß gerade auf ein ähnliches Problem mit SGE, und keine suggested method zu "unbuffer" die Datei IO schien für mich zu arbeiten. Ich musste bis zum Ende der Programmausführung warten, um eine Ausgabe zu sehen.

Die Problemumgehung, die ich fand, bestand darin, sys.stdout in ein benutzerdefiniertes Objekt zu verpacken, das die Methode "write" erneut implementiert. Anstatt tatsächlich in stdout zu schreiben, öffnet diese neue Methode stattdessen die Datei, in der IO umgeleitet wird, hängt mit den gewünschten Daten an und schließt dann die Datei. Es ist ein bisschen hässlich, aber ich fand es das Problem gelöst, da das tatsächliche Öffnen/Schließen der Datei IO interaktiv zwingt.

Hier ist ein minimales Beispiel:

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

Diese SGE den Ausgang des Prozesses puffert, es geschieht, ob ihr ein Python-Prozess oder jede andere.

Im Allgemeinen können Sie die Pufferung in SGE verringern oder deaktivieren, indem Sie sie ändern und neu kompilieren. Aber es ist keine großartige Sache, all diese Daten werden langsam auf die Festplatte geschrieben, was sich auf Ihre Gesamtleistung auswirkt.

0

Dies funktioniert für mich:

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) 

und das Problem hat mit NFS nicht synchronisiert Daten zurück an den Master zu tun, bis eine Datei geschlossen wird oder fsync genannt wird.

4

Wie andere erwähnt haben, ist es aus Leistungsgründen nicht immer die STDOUT zu schreiben, wenn sie nicht mit einem TTY verbunden ist.

Wenn Sie einen bestimmten Punkt haben, an dem Sie die stdout wollen geschrieben werden, können Sie diese Kraft durch

import sys 
sys.stdout.flush() 

an diesem Punkt mit.

0

Warum nicht in eine Datei anstelle von stdout drucken?

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

und

tail -f output.log 
0

verwende ich traf das gleiche Problem heute und löste es, indem nur statt Druck auf die Platte geschrieben:

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