简体   繁体   English

Python,非阻塞 pipe,刷新,缺少标准输出/标准错误

[英]Python, non-blocking pipe, flushing, and missing stdout/stderr

I have two python processes connected by a pipe. The pipe was created with:我有两个由 pipe 连接的 python 进程。pipe 是用以下命令创建的:

read_file_descriptor, write_file_descriptor = os.pipe()
os.set_blocking(read_file_descriptor, False)
os.set_inheritable(read_file_descriptor, True)

The parent process forks off a child, and the child reads from the read file descriptor using code that in essence boils down to this:父进程分叉出一个子进程,子进程使用本质上归结为以下代码的代码从读取的文件描述符中读取:

lines = []
read_handle = os.fdopen(read_file_descriptor)
while True:
    line = read_handle.readline()
    if _TERMINATION_CHAR in line:
        # trigger final upload
        line = line[: line.index(_TERMINATION_CHAR)]
        received_stream_termination = True
    elif len(line) == 0:
        # The line would at least have the newline char if it was a blank.

        # no more to read right now; just keep looping and trying to read
        # until the timeout or the termination character tell us to stop
        time.sleep(0.01)
        continue

    fp.write(line)
    fp.flush()
    if received_stream_termination:
        break
# handle lines...

The parent process, meanwhile, redirects its stdout and stderr to point at the write_file_descriptor .与此同时,父进程将其 stdout 和 stderr 重定向到指向write_file_descriptor When the parent is done, it does:当父母完成后,它会:

logger.info("Cleaning up")
print(_TERMINATION_CHAR)  # tell the reader that the stream is done
sys.stdout.flush()
sys.stderr.flush()

The process is running with PYTHONUNBUFFERED=1 set in the environment.该进程在环境中设置PYTHONUNBUFFERED=1的情况下运行。 I am stressing this code by having the parent write ~20k lines (10k each to stdout and stderr, interleaved):我通过让父级编写 ~20k 行(每行 10k 到 stdout 和 stderr,交错)来强调这段代码:

    for i in range(10000):
        time.sleep(0.01)
        print(f"From stdout: {i}")
        print(f"From stderr: {i}", file=sys.stderr)

    return a + b

With this, the lines the handler sees are:这样,处理程序看到的行是:

# ... there are more lines before this. Nothing seems to be missing up to this point
From stdout: 9012
From stderr: 9012
From stdout: 9013
From stderr: 9013
From stdout: 9014
From stderr: 9014
From stdout: 9015
From stderr: 9015
2022-11-15 23:01:28,536 - INFO : Cleaning up

So... a lot of lines at the end are missing.所以...最后有很多行都丢失了。 But we still see the log message.但是我们仍然看到日志消息。 Any ideas why this may be happening?为什么会发生这种情况的任何想法?

The problem turned out to be a race condition between two different mechanisms for indicating completion.问题原来是两种不同的指示完成机制之间的竞争条件。 One mechanism was the termination character, the other was a sigterm handler.一种机制是终止字符,另一种是 sigterm 处理程序。 The sigterm was sent between when the print statements completed their execution and when the terminating character was written. sigterm 在打印语句完成执行和写入终止字符之间发送。 Simplifying to always use the termination character only solved the issue.简化为始终使用终止符只能解决问题。 So nothing funky with i/o, just your run-of-the-mill race condition!所以 I/O 没有什么奇怪的,只是你的普通比赛条件!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM