如何在Windows上无阻塞地从python子进程popen读取标准输出?
我正遭受Windows Python子流程模块的困扰。如何在Windows上无阻塞地从python子进程popen读取标准输出?,python,python-3.x,subprocess,Python,Python 3.x,Subprocess,我正遭受Windows Python子流程模块的困扰。 这是测试代码1(名为test1.py): 和测试代码2(名为test2.py): 通常,测试代码2生成随机整数(0~100)并无限打印出来。 我希望测试代码1创建一个子进程并启动它,实时读取标准输出(不要等待子进程完成)。 但当我运行代码时,输出是: python.exe test1.py parent process 它会永远阻塞stdout.read()。 我试过: 用communicate()替换stdout.read,不按预期工作
这是测试代码1(名为test1.py): 和测试代码2(名为
test2.py
):
通常,测试代码2生成随机整数(0~100)并无限打印出来。
我希望测试代码1创建一个子进程并启动它,实时读取标准输出(不要等待子进程完成)。
但当我运行代码时,输出是:
python.exe test1.py
parent process
它会永远阻塞stdout.read()。
我试过:
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:
test1.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")
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")
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
解决方案2:
test1.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")
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")
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
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'
您可以通过在参数中提供编码
或提供universal\u newlines=True
将管道切换到文本模式,这将使其使用默认编码。然后直接写入父进程的sys.stdout
。这基本上将子进程的输出流到父进程的输出
test1.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")
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")
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
有什么理由特别需要是
Popen
?为什么不使用子流程。检查\u输出
?或者,check\u output
不进行实时读取吗?@NiemaMoshiri是的,check\u output
类似于run
,它会一直返回,直到子进程终止。您指出关键——子进程输出缓冲!谢谢Nikita,这两种解决方案都很好。这是一个测试代码,用于在子进程和父进程之间传输数据(大数据)。所以字节格式是可以的,您在循环中使用poll()的示例也适用于我。再次感谢你!