首页 > 解决方案 > 如何在 Python 子进程中立即读取标准输出

问题描述

我正在尝试制作两个 python 进程。

主文件

child = Popen(['python.exe', 'test.py'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
stdout, stderr = child.communicate(input='hello world'.encode())
result = stdout.decode()
print(result)

测试.py

value = sys.stdin.read()
sys.stdout.write(value)
time.sleep(10)

(time.sleep 只是一个耗时任务的例子。)

在这种情况下,打印前main.py等待 10 秒test.py以结束。

有没有办法在test.py之后立即打印标准输出sys.stdout.write

标签: pythonsubprocess

解决方案


为您举一个例子,您多次阅读和写信给孩子(正如您在问题下的评论中所述)。

子进程 ( test.py) 将:

  • 读一行
  • 将每个转换为大写,然后写回,
  • 睡眠 2 秒
  • 重复直到没有更多输入,然后写最后一行

主进程 ( main.py) 将:

  • 三次:
    • 向子进程写入一行输入
    • 阅读答案并说出需要多长时间才能得到答案
    • 睡眠 5 秒
  • 最后,使用 读取任何最终输出communicate,并报告此内容

这是代码的输出,如下所示:

writing to child: hello world 0
child replied with: HELLO WORLD 0
got answer back within 0.00022 seconds

writing to child: hello world 1
child replied with: HELLO WORLD 1
got answer back within 0.00012 seconds

writing to child: hello world 2
child replied with: HELLO WORLD 2
got answer back within 0.00021 seconds

final output from child: finishing

这是代码:

test.py

import sys
import time

while True:
    value = sys.stdin.readline()
    if not value:
        break
    sys.stdout.write(value.upper())
    sys.stdout.flush()
    time.sleep(2)

sys.stdout.write("finishing\n")

main.py

from subprocess import Popen, PIPE, STDOUT
import time

child = Popen(['python.exe', 'test.py'], stdin=PIPE, stdout=PIPE, stderr=STDOUT)
time.sleep(1)

for i in range(3):
    data_in = f"hello world {i}"
    print(f"writing to child: {data_in}")

    time0 = time.time()
    child.stdin.write(f"{data_in}\n".encode())
    child.stdin.flush()
    data_out = child.stdout.readline()
    time1 = time.time()
    
    result = data_out.decode().strip()
    elapsed_time = time1 - time0
    print(f"child replied with: {result}")
    print(f"got answer back within {elapsed_time:.5f} seconds\n")
    time.sleep(5)

output, error = child.communicate()
print(f"final output from child: {output.decode()}")

(在 Linux 上使用python而不是测试python.exe- 希望它在 Windows 上同样有效,尽管我无法测试。)

如您所见,无需等待sleep完成即可收到答案。

(显然,如果父母的睡眠时间减少到大约 2 秒以下,那么孩子在发送数据时将无法接收数据,因此需要等待更多时间才能得到答复。)

通过这种双向通信,很容易陷入死锁情况(每个进程都在等待另一个进程做某事)。为避免这种情况,每个进程每次只写入一行,确保它以换行符结束,并立即刷新输出缓冲区 - 读取过程用于readline()读取准确的一行(读取直到换行)。然后希望两者应该保持一致并避免僵局。


推荐阅读