我有一个简单的python脚本,在随机输出量后会死掉。
恕我直言 - 它应该起作用
这是linux特定的,python2或python3同样的问题;不确定python-mac - 我没有mac方便;并不是一个python-windows问题。
我认为问题在于Linux解释stdio阻塞或非阻塞。在我看来,在很大程度上我相信Pythons认为STDIN和STDOUT是两个不同的文件。
这篇文章谈到了C代码方面的问题: When non-blocking I/O is turned on for stdout, is it correct for the OS to turn it on for stdin too?
问题:在STDIN上,在STDIN上设置os.O_NONBLOCK选项。
预期结果:
O_NONBLOCK应仅适用于它所应用的文件。
实际结果:
在STDIN和STDOUT上都设置了O_NONBLOCK
结果:当你的应用程序以某种方式以标准方式(例如输出日志或调试信息)写入stdout(或stderr)时,某些时候python2或python3会在以后的某个随机时间点以IO错误退出。
下面的代码演示了问题
import sys
import fcntl
import os
def show_flags(why):
print("%s: FLAGS: 0x%08x" % (why,fcntl.fcntl( sys.stdout.fileno(), fcntl.F_GETFL )))
show_flags("startup")
f = fcntl.fcntl( sys.stdin.fileno(), fcntl.F_GETFL )
show_flags("got-stdin")
f = f | os.O_NONBLOCK
fcntl.fcntl( sys.stdin.fileno(), fcntl.F_SETFL, f )
show_flags("set-stdin")
# produce spewing output to show the error.
for x in range(0,10000):
sys.stdout.write("x=%10d -------- lots of text here to fill buffer\n" % x)
如果我运行:“strace -o log python test.py” - 并捕获日志输出 显示错误的相关部分是:
(开始)
fcntl(1, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
write(1, "startup: FLAGS: 0x00008002\n", 27) = 27
fcntl(0, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
fcntl(1, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
write(1, "got-stdin: FLAGS: 0x00008002\n", 29) = 29
fcntl(0, F_SETFL, O_RDWR|O_NONBLOCK|O_LARGEFILE) = 0
fcntl(1, F_GETFL) = 0x8802 (flags O_RDWR|O_NONBLOCK|O_LARGEFILE)
write(1, "set-stdin: FLAGS: 0x00008802\n", 29) = 29
write(1, "x= 0 -------- lots of te"..., 55) = 55
write(1, "x= 1 -------- lots of te"..., 55) = 55
在一些随机数量的写入(300到500)之后,linux返回错误
write(1, "x= 495 -------- lots of te"..., 55) = 55
write(1, "x= 496 -------- lots of te"..., 55) = -1 EAGAIN (Resource temporarily unavailable)
write(2, "Traceback (most recent call last"..., 35) = -1 EAGAIN (Resource temporarily unavailable)
建议?
我不能轻易进入一个喜欢调试日志输出的相当大的应用程序...
问题:应用程序希望/需要以非阻塞方式监视/读取STDIN,以便它可以处理来自父级的输出并对其进行操作。编写日志不应导致应用程序在随机位置死亡。
用“try / catch”块包装每个日志语句都是精神错乱。
要求linux众神改变这种行为不会发生。
Python3 - 似乎至少重试一次,有时会成功,但大部分时间都没有 - Python2根本不会重试。
通过自定义黑客修复此 INSIDE python也是疯狂的...我无法轻松地将我的Python.EXE自定义版本分发给需要运行我的应用程序的每个人。
建议?