Skip to content Skip to sidebar Skip to footer

Why Does Asyncio Subprocess Behave Differently With Created Event Loop Unless You Set_event_loop?

I have this simple async code that spawns sleep 3 and then waits for it to complete: from asyncio import SelectorEventLoop, create_subprocess_exec, \ wait_for, get_event_loop,

Solution 1:

It's really strange. I debugged the program and found that is hard to say if it is a bug.

Let's make a long story short, when executing create_subprocess_exec, you need not only an event loop but also a child watcher(which is used to monitor child processes). But create_subprocess_exec doesn't provide a way to let you set custom child watcher, it just use the default watcher which attaches to the default event loop but not current running event loop.

If you use the following code, it will work:

from asyncio import SelectorEventLoop, create_subprocess_exec, \
    wait_for, get_event_loop, set_event_loop, get_child_watcher


def run_timeout(loop, awaitable, timeout):
    timed_awaitable = wait_for(awaitable, timeout=timeout)
    return loop.run_until_complete(timed_awaitable)

async def foo():
    process = await create_subprocess_exec('sleep', '3')
    await process.wait()
    print(process.returncode)

loop = SelectorEventLoop()
# core line, get default child watcher and attach it to your custom loop.
get_child_watcher().attach_loop(loop)
run_timeout(loop, foo(), 5)
loop.close()

And if you use set_event_loop to set default loop, it will also reattach the default child watcher to new default loop. That's why it works.


It's really hard to say if it is a bug or a problem about API design. Should create_subprocess_exec let you pass a custom watcher? If it should, it will make confusion as you will only touch child watcher when you are working with child processes.


Post a Comment for "Why Does Asyncio Subprocess Behave Differently With Created Event Loop Unless You Set_event_loop?"