繁体   English   中英

Python asyncio:在辅助线程上运行subprocess_exec

[英]Python asyncio: Running subprocess_exec on a worker thread

因此,我正在使用Python asyncio模块(在Linux上)启动子进程,然后对其进行异步监视。 我的代码在主线程上运行时工作正常。 但是,当我在辅助线程上运行它时,它将挂起,并且永远不会调用process_exited回调。

我怀疑这实际上可能是某种未记录的缺陷,或者是在工作线程上运行subprocess_exec问题,可能与实现如何处理后台线程中的信号有关。 但这也可能只是我搞砸了。

一个简单的,可复制的示例如下:

class MyProtocol(asyncio.SubprocessProtocol):
    def __init__(self, done_future):
        super().__init__()
        self._done_future = done_future

    def pipe_data_received(self, fd, data):
        print("Received:", len(data))

    def process_exited(self):
        print("PROCESS EXITED!")
        self._done_future.set_result(None)

def run(loop):
    done_future = asyncio.Future(loop = loop)
    transport = None
    try:
        transport, protocol = yield from loop.subprocess_exec(
            lambda : MyProtocol(done_future),
            "ls",
            "-lh",
            stdin = None
        )
        yield from done_future
    finally:
        if transport: transport.close()

    return done_future.result()

def run_loop():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop) # bind event loop to current thread

    try:
        return loop.run_until_complete(run(loop))
    finally:
        loop.close()

因此,在这里,我设置了一个asyncio事件循环来执行shell命令ls -lh ,然后为从子流程接收到数据时触发一个回调,为子流程退出时触发另一个回调。

如果我只是直接在Python程序的主线程中调用run_loop() ,那么一切都会顺利进行。 但是如果我说:

t = threading.Thread(target = run_loop)
t.start()
t.join()

然后发生的事情是成功调用了pipe_data_received()回调,但是从未调用过process_exited() ,并且程序仅挂起。

在四处asyncio并查看了asyncio的实现的asyncio源代码unix_events.py ,我发现可能有必要将事件循环手动附加到全局“ child watcher”对象,如下所示:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) # bind event loop to current thread
asyncio.get_child_watcher().attach_loop(loop)

显然,儿童观察者是一个(未记录的)对象,负责在内部调用waitpid (或类似的东西)。 但是,当我尝试这样做并在后台线程中运行run_event_loop()时,出现了错误:

  File "/usr/lib/python3.4/asyncio/unix_events.py", line 77, in add_signal_handler
    raise RuntimeError(str(exc))
RuntimeError: set_wakeup_fd only works in main thread

因此,这里看起来该实现实际上进行了检查,以确保只能在主线程上使用信号处理程序,这使我相信,在当前实现中,实际上在后台线程上使用subprocess_exec是完全不可能的,而无需更改Python源代码本身。

我对此是否正确? 可悲的是, asyncio模块的文档非常少,所以我很难对这里的结论充满信心。 我可能做错了什么。

只要在主线程中运行asyncio循环且其子监视程序实例化,就可以在辅助线程中处理子进程:

asyncio.get_child_watcher()
loop = asyncio.get_event_loop()
coro = loop.run_in_executor(None, run_loop)
loop.run_until_complete(coro)

请参阅这篇文章文档

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM