使用文件记录器时,stderr 在 stdout 之前刷新

使用文件记录器时,stderr 在 stdout 之前刷新

我的Python代码:

import sys
print "i am a daemon"
print "i will be run using nohup"
sys.stderr.write("i am an error message inside nohup process\n")

当我运行代码时python a.py,它显示,

i am a daemon
i will be run using nohup
i am an error message inside nohup process

当我运行代码时nohup python a.py > a.log 2>&1 < /dev/null &,a.log 显示,

i am an error message inside nohup process
i am a daemon
i will be run using nohup

为什么使用时 stderr 日志会在 stdout 日志之前刷新/写入nohup

答案1

我不认为这有什么关系nohup。当您这样做时,您会得到相同的行为python a.py > a.log 2>&1

Python 很可能在底层使用 C 文件 stdio。这样,stdout当在终端中时,将进行行缓冲,并在stdout是文件时进行缓冲。stderr始终是无缓冲的。

重定向stdout到文件会将stdout的缓冲从行缓冲切换为缓冲,并导致printed 字符串卡在缓冲区中,只有当程序(流)关闭时才会刷新。由于流stderr是无缓冲的,因此它可以更快地传输到文件。

您可以使用stdbuf调整标准缓冲,强制行以正确的顺序打印:

stdbuf -o0 python a.py  >a.log 2>&1

答案2

这是大多数语言中输出流的正常行为:它们是缓冲的,即write实际上写入内存中的缓冲区,并且该缓冲区被批量写出到流中。当写入终端时,标准输出是行缓冲的(即每次打印换行符时都会发生实际写入),但当写入常规文件或管道时,标准输出是完全缓冲的(数据被写入内存,直到内存缓冲区变满)。 Stderr 要么是无缓冲的,要么是行缓冲的。

在Python中,您可以在打开文件时选择缓冲类型,但不能选择标准流。如果您希望所有流都是无缓冲的,您可以设置PYTHONUNBUFFERED环境变量强制标准流不被缓冲。或者,您可以stdbuf在或下运行程序unbuffer

但是,如果您的程序在标准输出重定向时没有以适当的顺序发出输出,则这是程序中的缺陷,您应该修复该缺陷。特别是,如果您要发出与写入 stdout 的输出有关的错误消息,则应首先刷新 stdout:

print some_data
if errro_condition():
    file.stdout.flush()
    sys.stderr.write('Bad stuff happened\n')

相关内容