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,代码将正常工作。