为什么自定义协程调用时不会调用_run_once?

问题描述 投票:0回答:1

我做了什么

async def inner() -> None:
    print("inner")


async def main() -> None:
    print("main start")
    await inner()
    print("main end")


if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

我在 asyncio 的事件循环中添加了一些 print()

    def run_forever(self):
        """Run until stop() is called."""

        try:
            self._thread_id = threading.get_ident()
            sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook,
                                   finalizer=self._asyncgen_finalizer_hook)

            events._set_running_loop(self)
            print("start loop in run_forever"). # here!
            while True:
                self._run_once()
                if self._stopping:
                    break



    def _run_once(self):
        """Run one full iteration of the event loop.

        This calls all currently ready callbacks, polls for I/O,
        schedules the resulting callbacks, and finally schedules
        'call_later' callbacks.
        """
        print("_run_once called!")  # here!
        sched_count = len(self._scheduled)
        if (sched_count > _MIN_SCHEDULED_TIMER_HANDLES and
        ...

我以为会发生什么

  1. 协程 main() 由事件循环调用
  2. 协程inner()被注册到事件循环
  3. 事件循环在
    _run_once()
  4. 中调用inner()

到底发生了什么

  1. main() 被事件循环调用(通过 _run_once())
  2. main调用inner()
  3. inner() 完成(事件循环中没有交互)

日志

start loop in run_forever
_run_once called!
main start
inner
main end
_run_once called!
start loop in run_forever
_run_once called!
_run_once called!
start loop in run_forever
_run_once called!
_run_once called!

问题

  1. 为什么会这样?
  2. 协程inner()到底是什么?
python python-asyncio
1个回答
0
投票

为什么出现三个“start loop in run_forever”消息?

循环在

asyncio.run
中启动了3次(参见
asyncio/runners.py
中的源代码):

  • 运行
    main
  • 清理:关闭异步生成器
  • cleanup:关闭默认执行器

为什么整个程序是在一个循环迭代中执行的? (希望我答对了问题)

await another_coro()
不直接与事件循环交互。它与
yield from
非常相似,即它与
another_coro()
建立双向连接,然后程序继续运行。如果该协程等待另一个协程等,则会形成所有这些
yield from
-s 的管道。只有
await future_not_done_yet
与循环交互,因为它通过该管道将 future 发送到事件循环(与
yield
非常相似)并且循环做出反应:它将当前任务标记为等待刚刚接收到的 future 并调度(使用
call_soon
)可运行任务集中的另一个任务将在下一次循环迭代期间运行。

© www.soinside.com 2019 - 2024. All rights reserved.