为什么asyncio子进程的行为与创建的事件循环不同,除非设置了“事件”循环?

2024-06-27 02:22:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个简单的异步代码,它生成sleep 3,然后等待它完成:

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


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

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

请注意自定义loop。如果我使用以下命令运行它:

^{pr2}$

它按预期工作(3秒后sleep 3成功完成,并打印0)。但是,如果我用自己的事件循环运行它:

loop = SelectorEventLoop()
run_timeout(loop, foo(loop), 5)
loop.close()

我得到一个TimeoutError(来自run_timeout中的wait_for):

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    _run_async(loop, foo(loop), 5)
  File "test.py", line 7, in _run_async
    return loop.run_until_complete(timed_coroutine)
  File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "/usr/lib/python3.5/asyncio/tasks.py", line 396, in wait_for
    raise futures.TimeoutError()
concurrent.futures._base.TimeoutError

使自定义事件循环工作的唯一方法是在创建自己的SelectorEventLoop之后set_event_loop()

loop = SelectorEventLoop()
set_event_loop(loop)
run_timeout(loop, foo(loop), 3)
loop.close()

这是什么?我误解了文件吗?所有事件循环(您所使用的)都必须成为默认循环吗?如果是这样,那么允许将自定义loop传递到许多异步方法(例如create_subprocess_execwait_for)中似乎是没有用的,因为您可以传入的唯一值是get_event_loop(),这是默认值。在


Tags: runinpyloopeventasyncioforfoo
1条回答
网友
1楼 · 发布于 2024-06-27 02:22:29

真的很奇怪。我调试了这个程序,发现很难说是不是一个bug。在

长话短说,在执行create_subprocess_exec时,不仅需要一个事件循环,还需要一个子观察程序(用于监视子进程)。但是create_subprocess_exec没有提供一种方法来允许您设置自定义子观察程序,它只是使用默认的观察程序,它附加到默认事件循环,而不是当前正在运行的事件循环。在

如果使用以下代码,它将起作用:

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()

{reatcher}还将使用默认值为^新的循环,并将其设置为默认值。这就是它起作用的原因。在


很难说这是一个错误还是API设计的问题。create_subprocess_exec是否应该允许您传递自定义观察程序?如果应该的话,它会造成混淆,因为在处理子进程时,您只会接触子观察程序。在

相关问题 更多 >