[英]Python, non-blocking pipe, flushing, and missing stdout/stderr
我有兩個由 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)
父進程分叉出一個子進程,子進程使用本質上歸結為以下代碼的代碼從讀取的文件描述符中讀取:
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...
與此同時,父進程將其 stdout 和 stderr 重定向到指向write_file_descriptor
。 當父母完成后,它會:
logger.info("Cleaning up")
print(_TERMINATION_CHAR) # tell the reader that the stream is done
sys.stdout.flush()
sys.stderr.flush()
該進程在環境中設置PYTHONUNBUFFERED=1
的情況下運行。 我通過讓父級編寫 ~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
這樣,處理程序看到的行是:
# ... 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
所以...最后有很多行都丟失了。 但是我們仍然看到日志消息。 為什么會發生這種情況的任何想法?
問題原來是兩種不同的指示完成機制之間的競爭條件。 一種機制是終止字符,另一種是 sigterm 處理程序。 sigterm 在打印語句完成執行和寫入終止字符之間發送。 簡化為始終使用終止符只能解決問題。 所以 I/O 沒有什么奇怪的,只是你的普通比賽條件!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.