5

我有一个 SGE 脚本来执行一些 python 代码,使用 qsub 提交到队列。在 python 脚本中,我有一些打印语句(向我更新程序的进度)。当我从命令行运行 python 脚本时,打印语句被发送到标准输出。对于 sge 脚本,我使用 -o 选项将输出重定向到文件。但是,似乎脚本只会在 python 脚本完成运行后将这些发送到文件中。这很烦人,因为 (a) 我无法再看到程序的实时更新,并且 (b) 如果我的作业没有正确终止(例如,如果我的作业被踢出队列),则不会打印任何更新。我如何确保每次我想打印某些东西时脚本都在写入文件,而不是在最后将它们混为一谈?

4

7 回答 7

7

我认为您遇到了缓冲输出的问题。Python 使用一个库来处理它的输出,并且该库知道在它不与 tty 对话时编写一个块更有效。

有几种方法可以解决这个问题。例如,您可以使用“-u”选项运行 python(有关详细信息,请参见 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 做类似的事情。

于 2012-03-26T18:04:01.560 回答
6

正如其他人所提到的,在未连接到 tty 时并不总是写入标准输出是出于性能原因。

如果您有一个特定的点想要写入标准输出,您可以通过使用强制执行该点

import sys
sys.stdout.flush()

在那时候。

于 2015-12-18T17:24:59.147 回答
3

我刚刚遇到了与 SGE 类似的问题,并且没有建议的方法来“取消缓冲”文件 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()
于 2012-10-29T17:45:50.343 回答
3

这是 SGE 缓冲进程的输出,无论它是 python 进程还是其他任何进程都会发生。

通常,您可以通过更改和重新编译来减少或禁用 SGE 中的缓冲。但这不是一件好事,所有数据都会慢慢写入磁盘,影响您的整体性能。

于 2013-03-11T17:33:51.067 回答
1

为什么不打印到文件而不是标准输出?

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

并使用

tail -f output.log
于 2015-12-24T01:57:06.843 回答
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)

这个问题与 NFS 在关闭文件或调用 fsync 之前不会将数据同步回主服务器有关。

于 2015-07-20T19:59:49.907 回答
0

我今天遇到了同样的问题,并通过写入磁盘而不是打印来解决它:

with open('log-file.txt','w') as out:
  out.write(status_report)
于 2017-07-28T00:34:56.833 回答