gpt4 book ai didi

python - 如何在 Windows 上非阻塞地从 python 子进程 popen 读取 stdout?

转载 作者:行者123 更新时间:2023-12-01 02:17:31 25 4
gpt4 key购买 nike

我正遭受 Windows Python 子进程模块的困扰。
这是测试代码1(名为test1.py):

import subprocess as sbp


with sbp.Popen('python tests/test2.py',stdout=sbp.PIPE) as proc:
print('parent process')
print(proc.stdout.read(1))
print('end.')

和测试代码2(名为test2.py):

import random
import time

def r():
while True:
yield random.randint(0, 100)


for i in r():
print(i)
time.sleep(1)

一般情况下,测试代码2会生成随机整数(0~100)并无限打印出来。我希望测试代码1创建一个子进程并启动它,实时读取标准输出(不等待子进程完成)。但是当我运行代码时,输​​出是:

python.exe test1.py
parent process

它永远阻塞在 stdout.read() 上。我尝试过:

  1. stdout.read 替换为communicate(),不起作用 python doc正如预期,它将阻塞直到子进程终止。
  2. 使用 poll() 方法检测子进程并读取 n 个字节,在 read() 上永远阻塞
  3. 修改test2.code,只生成一个数字并打破循环。父进程立即打印出来(我认为这是因为子进程终止了)

我搜索了很多类似的答案并按照他们的建议做了(使用标准输出而不是通信),但仍然不起作用?

有人可以帮我解释一下为什么以及如何做吗?

这是我的平台信息:
Win32 上的 Python 3.6.4(v3.6.4:d48eceb,2017 年 12 月 19 日,06:54:40)[MSC v.1900 64 位 (AMD64)]

最佳答案

它与 Python 的输出缓冲有关(对于您的情况下的子进程)。尝试禁用缓冲,您的代码应该可以工作。您可以通过使用 -u 键运行 python,或调用 sys.stdout.flush() 来完成此操作。

要使用-u键,您需要修改Popen调用中的参数,以使用flush()调用您需要修改test2.py

此外,您的 test1.py 只会打印一个数字,因为您只从管道中读取 1 个字节,而不是在循环中读取它们。

解决方案1:

测试1.py

import subprocess as sbp

with sbp.Popen(["python3", "-u", "./test2.py"], stdout=sbp.PIPE) as proc:
print("parent process")
while proc.poll() is None: # Check the the child process is still running
data = proc.stdout.read(1) # Note: it reads as binary, not text
print(data)
print("end")

这样您就根本不必接触 test2.py

解决方案2:

测试1.py

import subprocess as sbp

with sbp.Popen("./test2.py", stdout=sbp.PIPE) as proc:
print("parent process")
while proc.poll() is None: # Check the the child process is still running
data = proc.stdout.read(1) # Note: it reads as binary, not text
print(data)
print("end")

测试2.py

import random
import time
import sys

def r():
while True:
yield random.randint(0, 100)

for i in r():
print(i)
sys.stdout.flush() # Here you force Python to instantly flush the buffer
time.sleep(1)

这将在新行上打印每个接收到的字节,例如:

parent process
b'9'
b'5'
b'\n'
b'2'
b'6'
b'\n'

您可以通过在参数中提供 encoding 或提供 universal_newlines=True 将管道切换到文本模式,这将使其使用默认编码。然后直接写入父进程的 sys.stdout 。这基本上会将子进程的输出流式传输到父进程的输出。

测试1.py

import subprocess as sbp
import sys

with sbp.Popen("./test2.py", stdout=sbp.PIPE, universal_newlines=True) as proc:
print("parent process")
while proc.poll() is None: # Check the the child process is still running
data = proc.stdout.read(1) # Note: it reads as binary, not text
sys.stdout.write(data)
print("end")

这将提供输出,就像直接执行 test2.py 一样:

parent process
33
94
27

关于python - 如何在 Windows 上非阻塞地从 python 子进程 popen 读取 stdout?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48259183/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com