2012-03-26 64 views
5

我有一個SGE腳本來執行一些使用qsub提交給隊列的python代碼。在python腳本中,我有幾個打印語句(更新程序的進度)。當我從命令行運行python腳本時,打印語句被髮送到stdout。對於sge腳本,我使用-o選項將輸出重定向到文件。但是,腳本似乎只會在python腳本運行完成後纔將這些文件發送到文件中。這很煩人,因爲(a)我再也看不到程序的實時更新,以及(b)如果我的作業沒有正確終止(例如,如果我的作業從隊列中被踢出),則沒有打印任何更新。我怎樣才能確保每次我要打印文件時腳本都會寫入文件,而不是在最後把所有文件合併在一起?SGE腳本:在執行過程中打印到文件(不只是在最後)?

回答

5

我認爲你遇到了緩衝輸出的問題。 Python使用一個庫來處理它的輸出,並且庫知道當它不與一個tty交談時編寫一個塊會更高效。

有幾種方法可以解決這個問題。您可以通過「-u」選項(詳見蟒蛇手冊頁)運行python,例如,像這樣的東西作爲腳本的第一行:

#! /usr/bin/python -u 

但是,這並不工作,如果你正在使用「/ usr/bin/env」技巧,因爲你不知道python的安裝位置。

另一種方式是像這樣的東西重新打開標準輸出:

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) 

注os.fdopen的bufsize參數被設置爲0,迫使它是緩衝。你可以用sys.stderr做類似的事情。

+0

謝謝!沒有意識到這與Python有什麼關係。也發現這篇文章有幫助http://stackoverflow.com/questions/107705/python-output-buffering – miz 2012-03-26 18:12:23

3

我剛剛遇到了與SGE類似的問題,沒有suggested method來「緩衝」文件IO似乎爲我工作。我必須等到程序執行結束才能看到任何輸出。

我發現的解決方法是將sys.stdout包裝到重新實現「寫入」方法的自定義對象中。這種新方法不是實際寫入標準輸出,而是打開IO重定向的文件,追加所需數據,然後關閉文件。這有點難看,但我發現它解決了這個問題,因爲文件的實際打開/關閉迫使IO交互。

這裏有一個小例子:

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

這是上海黃金交易所的緩衝過程的輸出,它是否發生了一個Python程序或任何其他。

一般而言,您可以通過更改並重新編譯來減少或禁用SGE中的緩衝。但它不是一件好事,所有這些數據將會慢慢寫入磁盤,影響你的整體性能。

0

這個工作對我來說:

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) 

和問題有,直到文件被關閉或FSYNC被稱爲NFS不是主數據同步回做。

4

正如其他人所提到的,當沒有連接到tty時,出於性能原因不總是編寫stdout。

如果你有要被寫入標準輸出一個特定的點,你可以強制使用

import sys 
sys.stdout.flush() 

在這一點上。

0

爲什麼不打印到文件而不是標準輸出?

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

,並使用

tail -f output.log 
0

我今天打這個同樣的問題,僅通過寫磁盤,而不是印刷解決它:

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