'close' 使用 asyncio 的 python 子进程的事件侦听器

'close' event listener for python subprocess using asyncio

我正在尝试将事件侦听器附加到 python 子进程,只要进程 [​​=39=] 就会调用它。回调将重新生成子进程并将相同的事件侦听器附加到新的。

类似于在 node.js

中从 child_process 调用 .on

我知道 this thread already. But I'd ideally like to do this using asyncio.subprocess 而不是 运行 在单独的线程中设置每个事件侦听器。

我在想这样的事情-

from asyncio import subprocess as asubprocess
from typing import Callable, Awaitable

async def handle_close(proc: asubprocess.Process, spawner: Callable[[], Awaitable[asubprocess.Process]]):
    while True:
        await proc.wait()
        proc = await spawner()

(此函数也可以扩展为获取进程列表及其各自的生成器,并 asyncio.wait 所有这些,一旦其中任何一个停止 - 它们将重新生成并重复该过程)

proc 参数将是 asubprocess.create_subprocess_exec 返回的进程,而 spawner 将是重新生成该子进程的异步函数。 (或任何其他回调)

唯一的问题是,我不知道如何在后台 运行 这个而不用 async 污染我的整个代码库。理想情况下,将有多个子进程在后台需要它们自己的 handle_close。虽然所有这些处理程序都是 运行ning,但不应阻止调用者代码。

在我自己的用例中,我不需要进程句柄,因此可以丢弃这些句柄,只要进程保持 运行ning 和重生以防它们停止以及生成所有进程的调用者代码进程可以控制做其他事情,没关系。

The only issue is, I don't know how to run this in the background without polluting my entire codebase with async.

从这句话中并不能完全清楚实际的约束是什么,即您愿意使用异步代码走多远。通常假定使用 asyncio 的程序在 asyncio 事件循环中 运行,然后整个程序是异步的,即使用回调 and/or 协程。但是,如果您有一个使用阻塞代码和线程的大型代码库,您也可以在单独的线程中引入 asyncio。例如:

_loop = asyncio.new_event_loop()
def _run():
    asyncio.set_event_loop(_loop)
    _loop.run_forever()
threading.Thread(target=_run, daemon=True).start()

def async_submit(coro):
    return asyncio.run_coroutine_threadsafe(coro, _loop)

在后台使用事件循环 运行ning,您可以从阻塞代码中向它提交任务。例如:

from typing import List

async def handle_process(cmd: List[str]):
    while True:
        p = await asubprocess.create_subprocess_exec(*cmd)
        await p.wait()
        print('restarting', cmd)

# tell the event loop running in the background to respawn "sleep 1":
async_submit(handle_process(["sleep", "1"]))

请注意,所有与事件循环的交互都必须通过 run_coroutine_threadsafe 或其同类 call_soon_threadsafe 执行。