stdin上的非阻塞,stdout上的阻塞不起作用

时间:2017-11-27 02:06:58

标签: python linux nonblocking stdio

我有一个简单的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自定义版本分发给需要运行我的应用程序的每个人。

建议?

0 个答案:

没有答案