Python: 如何写入子进程的标准输入并实时读取其输出
Python: how to write to stdin of a subprocess and read its output in real time
我有 2 个程序。
第一个(实际上可以用任何语言编写,因此根本无法更改)如下所示:
#!/bin/env python3
import random
while True:
s = input() # get input from stdin
i = random.randint(0, len(s)) # process the input
print(f"New output {i}", flush=True) # prints processed input to stdout
它永远运行,从 stdin
读取一些东西,处理它并将结果写入 stdout
。
我正在尝试使用 asyncio
库在 Python 中编写第二个程序。
它将第一个程序作为子进程执行,并尝试通过其 stdin
为其提供输入并从其 stdout
.
检索结果
到目前为止,这是我的代码:
#!/bin/env python3
import asyncio
import asyncio.subprocess as asp
async def get_output(process, input):
out, err = await process.communicate(input)
print(err) # shows that the program crashes
return out
# other attempt to implement
process.stdin.write(input)
await process.stdin.drain() # flush input buffer
out = await process.stdout.read() # program is stuck here
return out
async def create_process(cmd):
process = await asp.create_subprocess_exec(
cmd, stdin=asp.PIPE, stdout=asp.PIPE, stderr=asp.PIPE)
return process
async def run():
process = await create_process("./test.py")
out = await get_output(process, b"input #1")
print(out) # b'New output 4'
out = await get_output(process, b"input #2")
print(out) # b''
out = await get_output(process, b"input #3")
print(out) # b''
out = await get_output(process, b"input #4")
print(out) # b''
async def main():
await asyncio.gather(run())
asyncio.run(main())
我很难实现 get_output
功能。它以字节字符串(.communicate()
方法的 input
参数需要)作为参数,将其写入程序的 stdin
,从其 stdout
读取响应return就这样了。
现在,只有第一次调用 get_output
可以正常工作。这是因为 .communicate()
方法的实现调用了 wait()
方法,有效地导致程序终止(这不是故意的)。这可以通过检查 get_output
函数中 err
的值来验证,它显示第一个程序到达 EOF
。因此,其他调用 get_output
return 一个空字节串。
我试过另一种方法,但不太成功,因为程序卡在了 out = await process.stdout.read()
行。我还没弄明白为什么。
我的问题是如何实现 get_output
函数来(近)实时捕获程序的输出并将其保存 运行 ?它不一定要使用 asyncio
,但我发现这个库是迄今为止最好的库。
提前致谢!
如果第一个程序保证只打印一行输出以响应它读取的输入行,您可以将 await process.stdout.read()
更改为 await process.stdout.readline()
,您的第二种方法应该有效.
它对您不起作用的原因是您的 run
函数有一个错误:它从不向子进程发送换行符。因此,子进程卡在 input()
并且永远不会响应。如果您在要传递给 get_output
的字节文字末尾添加 \n
,代码将正常工作。
我有 2 个程序。
第一个(实际上可以用任何语言编写,因此根本无法更改)如下所示:
#!/bin/env python3
import random
while True:
s = input() # get input from stdin
i = random.randint(0, len(s)) # process the input
print(f"New output {i}", flush=True) # prints processed input to stdout
它永远运行,从 stdin
读取一些东西,处理它并将结果写入 stdout
。
我正在尝试使用 asyncio
库在 Python 中编写第二个程序。
它将第一个程序作为子进程执行,并尝试通过其 stdin
为其提供输入并从其 stdout
.
到目前为止,这是我的代码:
#!/bin/env python3
import asyncio
import asyncio.subprocess as asp
async def get_output(process, input):
out, err = await process.communicate(input)
print(err) # shows that the program crashes
return out
# other attempt to implement
process.stdin.write(input)
await process.stdin.drain() # flush input buffer
out = await process.stdout.read() # program is stuck here
return out
async def create_process(cmd):
process = await asp.create_subprocess_exec(
cmd, stdin=asp.PIPE, stdout=asp.PIPE, stderr=asp.PIPE)
return process
async def run():
process = await create_process("./test.py")
out = await get_output(process, b"input #1")
print(out) # b'New output 4'
out = await get_output(process, b"input #2")
print(out) # b''
out = await get_output(process, b"input #3")
print(out) # b''
out = await get_output(process, b"input #4")
print(out) # b''
async def main():
await asyncio.gather(run())
asyncio.run(main())
我很难实现 get_output
功能。它以字节字符串(.communicate()
方法的 input
参数需要)作为参数,将其写入程序的 stdin
,从其 stdout
读取响应return就这样了。
现在,只有第一次调用 get_output
可以正常工作。这是因为 .communicate()
方法的实现调用了 wait()
方法,有效地导致程序终止(这不是故意的)。这可以通过检查 get_output
函数中 err
的值来验证,它显示第一个程序到达 EOF
。因此,其他调用 get_output
return 一个空字节串。
我试过另一种方法,但不太成功,因为程序卡在了 out = await process.stdout.read()
行。我还没弄明白为什么。
我的问题是如何实现 get_output
函数来(近)实时捕获程序的输出并将其保存 运行 ?它不一定要使用 asyncio
,但我发现这个库是迄今为止最好的库。
提前致谢!
如果第一个程序保证只打印一行输出以响应它读取的输入行,您可以将 await process.stdout.read()
更改为 await process.stdout.readline()
,您的第二种方法应该有效.
它对您不起作用的原因是您的 run
函数有一个错误:它从不向子进程发送换行符。因此,子进程卡在 input()
并且永远不会响应。如果您在要传递给 get_output
的字节文字末尾添加 \n
,代码将正常工作。