如何在 Python 子进程中立即读取标准输出

How to read stdout immediately in Python subprocess

我正在尝试创建两个 python 进程。

main.py

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)

test.py

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

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

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

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

一个给你的例子,你多次读写 child(正如你在问题下的评论中所说)。

子进程 (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 完成即可收到答案。

(显然如果parent中的休眠时间减少到2秒以下,那么child在发送数据时就不会准备好接收数据了,那么就会有等待得到答复。)

使用这种 two-way 通信,很容易陷入死锁状态(每个进程都在等待另一个进程做某事)。为避免这种情况,每个进程每次只写一行,确保它以换行符结尾,并立即刷新输出缓冲区——读取进程使用 readline() 只读取一行(读取到换行符)。那么希望两人能步调一致,避免僵局。