适当关闭asyncio进程而不会使其处于僵尸状态

时间:2020-03-05 09:58:44

标签: python asynchronous python-asyncio coroutine zombie-process

在我的程序中,我启动了几个asyncio.Process进程(使用create_subprocess_exec方法),我希望能够防止它们在终止时保持僵尸状态。我尝试使用child_watcher.add_child_handler(asyncio.event_loop_policy.child_watcher)方法将终止回调应用于该过程,但问题是该回调不能是协程,并且在回调内部需要等待proc.wait()才能进行确保进程不处于僵尸状态。您能否让我知道我的想法是否有缺陷或有其他解决方法?谢谢!

2 个答案:

答案 0 :(得分:1)

... proc.wait(),以确保进程未处于僵尸状态。您能否让我知道我的想法是否有缺陷或有其他解决方法?

您不需要为此使用儿童观察者。是的,您需要执行proc.wait()以确保该进程不会成为僵尸,但是您实际上并不需要 await ,您可以使用{ {1}}。例如:

create_task()

答案 1 :(得分:0)

在我的情况下,僵尸进程和无限wait / communicate是测试中错误配置新asyncio循环的结果。可以通过以下代码进行演示。

import asyncio
from asyncio.subprocess import PIPE

async def main():
    process = await asyncio.create_subprocess_exec(
        'echo', '42', stdout=PIPE, stderr=PIPE)
    print('pid', process.pid)
    stdout, stderr = await process.communicate()
    print('stdout', stdout)
    print('stderr', stderr)

if __name__  == '__main__':
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    # effective loop is not set to current context
    loop = asyncio.new_event_loop()  
    try:
        loop.run_until_complete(main())
    finally:
        loop.close()

此代码挂在await process.communicate()上。如果您ps的PID如下所示:

  PID TTY      STAT   TIME COMMAND
18399 pts/3    Z+     0:00 [echo] <defunct>

要解决此问题,只需添加丢失的set_event_loop呼叫即可设置儿童观察者(请参阅有关asyncio.get_child_watcher().attach_loop(loop) here的一些历史细节)。如果未设置上一个循环,则asyncio引发:

RuntimeError: Cannot add child handler, the child watcher does not have a loop attached

还请注意,如果您不需要直接与asyncio循环实例进行交互,则可以使用asyncio.run进行所有必要的设置和幕后拆卸。