2012-03-26 31 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)