繁体   English   中英

asyncio 的事件循环使用什么调度算法?

[英]What scheduling algorithm does asyncio's event loop use?

我查看了所有文档,但找不到它。

假设完成了多个await调用,并且它们的协程都准备好恢复,那么asyncio的事件循环使用什么算法来决定恢复哪个协程?

1) 文档向我们展示了事件循环以run_forever / run_until_complete开始。 我们需要找到函数的源代码,看看接下来会发生什么。

2)最快的方法(我知道)是在github上搜索相关名称。 转到github.com/python/cpython ,使用左上角的搜索表单:

在此处输入图像描述

Github 将向您显示项目中的所有事件。 确保在代码中搜索:

在此处输入图像描述

3)我们需要实现,找到了其中的两个: 一个在 ProactorEventLoop 内部,没有发生任何有趣的事情,因为它部分地重新实现了父事件循环; BaseEventLoop 里面的一个,它似乎是我们要搜索的。

4)让我们检查一下代码。 很快我们就会看到,一切都在while True循环中调用_run_once

try:
    events._set_running_loop(self)
    while True:
        self._run_once()
        if self._stopping:
            break

5)让我们_run_once (我们可以在页面上搜索def _run_once )。 这是恢复计划的事情的地方。 通过源代码,您会看到两个有趣的地方:

  • 符合event_list = self._selector.select(timeout) -这是 asyncio 休眠的地方,直到套接字上的活动。 您可以进一步阅读文档来研究此机制。 但是这个地方本身并没有恢复协程。
  • 我们读到的那一This is the only place where callbacks are actually *called*. All other places just add them to ready. This is the only place where callbacks are actually *called*. All other places just add them to ready.

正是我们搜索的内容。 您可以在那里阅读源代码(通常在_run_once函数内部)以查看回调是如何执行的,以及它们是如何添加到self._ready以执行的。 回调包括直接添加的回调和 asyncio 在内部用于恢复协程的回调。

您还可以重新实现事件循环来使用它。 看看这里的代码,它包含事件循环重新实现的示例。


几点注意事项:

  • 除非文档中另有说明,否则具体算法是实现的细节,可以在 asyncio 版本之间更改。 你不应该依赖它。
  • 不同的事件循环可以实现不同的算法。 虽然所有 asyncio 的循环似乎都在BaseEventLoop中使用一个,但其他事件循环(如自定义uvloop)可能会做一些不同的事情。
  • 通常为了找到我在 PyCharm 中使用ctrl+click的东西的源代码。 它比在 github 上搜索要快得多,也方便得多,但由于某种原因不能与 asyncio 一起使用。

如果您使用默认事件循环,python 3.10 中的 TLDR 准备恢复最长的协程将继续。 但是,每次执行事件循环时只会检查一次计时器(可能还有 io 事件)。


在内部BaseEventLoop保持一个双端队列self._ready包含所有准备好被调用的句柄。

句柄并不完全是协程,但与之相关。 实际上,asyncio.run 将协程包装在任务中,任务基本上将协程拆分为多个步骤,其中一个步骤是需要执行的所有内容,以到达协程中的下一个点,将控制权交还给事件循环(这可能晚于下一个等待语句,因为并非所有等待语句都将控制权交还给事件循环)。 句柄只是 asyncio 引用需要执行的步骤的内部方式。

句柄的执行顺序与它们放在_ready双端队列上的顺序相同。 此顺序取决于您的系统,并且在 Unix 上每次事件循环的迭代如下:

第一个。 自事件循环的上一次迭代以来,所有非 io、非基于计时器的句柄都按照这些准备就绪的顺序准备就绪。

第二。 所有基于 io 的句柄都按照它们在上一次迭代准备就绪后由 Unix select 系统调用返回的顺序排列。

第三。 所有基于计时器的句柄,其计时器已按顺序用完。

我没有检查,但我相信在 Windows 上使用基于前摄器的事件循环时,您会发现上面的第 1 点和第 2 点将按照它们准备好的顺序交错。


Mikhail Gerasimov已经给出的详细答案解释了如何找出标准事件循环在任何给定 python 版本中所做的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM