簡體   English   中英

除非你使用set_event_loop,為什么asyncio子進程與創建的事件循環的行為不同?

[英]Why does asyncio subprocess behave differently with created event loop unless you set_event_loop?

我有這個簡單的異步代碼產生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如何。 如果我運行以下內容:

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

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

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

我得到一個TimeoutError (來自run_timeoutwait_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() ,這是默認值。

真的很奇怪。 我調試了程序,發現如果它是一個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()

如果使用set_event_loop設置默認循環,它還會將默認子監視器重新set_event_loop到新的默認循環。 這就是它的原因。


很難說它是關於API設計的錯誤還是問題。 create_subprocess_exec是否允許您傳遞自定義觀察程序? 如果它應該,它會產生混淆,因為當你使用子進程時,你只會觸摸兒童觀察者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM