【发布时间】:2021-02-16 18:58:45
【问题描述】:
我有 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 读取响应并返回它。
现在,只有第一次调用 get_output 才能正常工作。这是因为.communicate() 方法的实现调用了wait() 方法,从而有效地导致程序终止(它不是故意的)。这可以通过检查get_output 函数中err 的值来验证,这表明第一个程序到达EOF。因此,对get_output 的其他调用返回一个空字节串。
我尝试了另一种方法,甚至不太成功,因为程序卡在out = await process.stdout.read() 行。我还没弄清楚为什么。
我的问题是如何实现get_output 函数以(近)实时捕获程序的输出并保持运行?它不必使用asyncio,但我发现这个库是迄今为止最好的。
提前谢谢你!
【问题讨论】:
-
第一个程序是否保证只打印一行输出以响应它已读取的输入行?如果是这样,您可以将
await process.stdout.read()更改为await process.stdout.readline(),您的第二种方法应该可以工作。 (它现在卡住了,因为它试图在 EOF 之前读取所有内容,并且您的第一个程序永远不会退出,所以 EOF 永远不会发生。) -
如果第一个程序不能保证只打印一行输出,那么这个如何实现就不清楚了,因为没有办法知道多少要读取的数据。
-
@user4815162342
.read(n)和.readline()不起作用。实际上,没有.read*()方法似乎有效。有没有办法queue 输出? -
我想我现在在您的代码中发现了问题 - 请参阅发布的答案。
标签: python-3.x subprocess python-asyncio stdout stdin