asyncio 的默认调度程序什么时候公平?

2023-12-23

我的理解是asyncio.gather旨在运行其参数同时此外,当协程执行等待表达式时,它为事件循环提供了安排其他任务的机会。考虑到这一点,我惊讶地发现以下代码片段忽略了其中一个输入asyncio.gather.

import asyncio                                                             
  
async def aprint(s):
    print(s)

async def forever(s):
    while True:
        await aprint(s)

async def main():
    await asyncio.gather(forever('a'), forever('b'))

asyncio.run(main())

据我了解,会发生以下情况:

  1. asyncio.run(main()) 对事件循环进行任何必要的全局初始化并安排 main() 执行。
  2. main() 安排 asyncio.gather(...) 执行并等待其结果
  3. asyncio.gather 安排forever('a') 和forever('b') 的执行
  4. 无论其中哪一个先执行,它们都会立即等待 aprint() 并让调度程序有机会在需要时运行另一个协程(例如,如果我们从“a”开始,那么我们就有机会开始尝试评估“b”,这应该已安排执行)。
  5. 在输出中,我们将看到一串行,每行都包含“a”或“b”,并且调度程序应该足够公平,以便我们在足够长的时间内至少看到其中的一行。

实际上,这不是我所观察到的。相反,整个程序相当于while True: print('a')。我发现非常有趣的是,即使对代码进行微小的更改似乎也会重新引入公平性。例如,如果我们使用以下代码,那么我们会在输出中得到大致相等的“a”和“b”混合。

async def forever(s):
    while True:
        await aprint(s)
        await asyncio.sleep(1.)

验证它似乎与我们在无限循环中和在无限循环外花费的时间没有任何关系,我发现以下更改也提供了公平性。

async def forever(s):
    while True:
        await aprint(s)
        await asyncio.sleep(0.)

有谁知道为什么会发生这种不公平现象以及如何避免它?我想,当有疑问时,我可以主动在各处添加一个空的睡眠语句,并希望这足够了,但对我来说,为什么原始代码的行为不符合预期,这对我来说非常不明显。

以防万一,因为 asyncio 似乎已经经历了相当多的 API 更改,我在 Ubuntu 机器上使用 Python 3.8.4 的普通安装。


  1. 无论哪一个先执行,它们都会立即执行await aprint()如果需要的话,让调度程序有机会运行另一个协程

这部分是一个常见的误解。蟒蛇的await并不意味着“将控制权交给事件循环”,它意味着“开始执行等待,allowing它让我们和它一起暂停”。所以是的,if等待的对象选择挂起,当前的协程也会挂起,等待它的协程也会挂起,依此类推,一直到事件循环。但如果等待的对象doesn't选择暂停,就像这样aprint,等待它的协程也不会。正如所见,这有时是错误的来源here https://stackoverflow.com/a/48816319/1600898 or here https://stackoverflow.com/a/53377822/1600898.

有谁知道为什么会发生这种不公平现象以及如何避免它?

幸运的是,这种效果在不真正与外界交流的玩具示例中最为明显。虽然你可以通过添加来修复它们await asyncio.sleep(0)到战略位置(甚至被记录为强制上下文切换),您可能不应该 https://stackoverflow.com/a/63437227/1600898在生产代码中执行此操作。

真正的程序将依赖于来自外部世界的输入,无论是来自网络、本地数据库的数据,还是来自由另一个线程或进程填充的工作队列的数据。实际数据很少会如此快地到达而导致程序的其余部分陷入饥饿,如果确实如此,饥饿可能是暂时的,因为程序最终会由于其自身的反压而挂起。output边。在极少数情况下,程序从一个源接收数据的速度比处理数据的速度快,但仍然需要观察来自另一个源的数据,您可能会遇到饥饿问题,但这可以通过强制上下文切换来解决if它曾经被证明会发生。 (我还没有听说有人在生产中遇到过它。)

除了上面提到的错误之外,更常见的情况是协程调用 CPU 密集型或遗留的阻塞代码,最终会占用事件循环。这种情况应该通过将 CPU/阻塞部分传递给run_in_executor https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

asyncio 的默认调度程序什么时候公平? 的相关文章

随机推荐

  • 如何在类库项目中使用 Server.MapPath

    我有一个包含许多类库项目的 Web 应用程序 下面是一些示例代码 public static class LenderBL static string LenderXml get return MyPathHere public stati
  • 发送大量消息 Kafka Producer

    我正在使用卡夫卡 我有一个包含 10k json 的列表 目前我发送的 Json 如下 for int i 0 i lt jsonList size i ProducerRecord
  • 通过单一表单更新多个模型

    嘿伙计们请帮助我 我想Update两个表数据通过单个表单 但数据仅在单个表中更新并插入到第二个表中 而不是更新现有记录 这是我的代码 查看文件 echo this gt Form gt create Question echo this g
  • 如何将我当前的项目添加到已有的 GitHub 存储库

    我对 Git 很陌生 我一直在寻找答案 但找不到答案 在我的计算机中 我有一个像这样的项目文件夹 project a some folder another folder git 假设我在 GitHub 上有一个存储库https githu
  • 有没有办法在模型而不是视图中使用pluralize()?

    它似乎pluralize只能在视图中工作 我的模型有什么方法可以使用pluralize too 我没有扩展东西 而是这样 ActionController Base helpers pluralize count mystring 希望这对
  • android 如何调整媒体播放器表面视图中的视频宽度和高度

    想要在表面视图中调整视频大小 我正在使用 Surface 视图和视频支架在媒体播放器中播放视频 但在某些设备 如 Micromax iball Akash 平板电脑 上实现 MediaPlayerControl 时 它会给出 ACRA 错误
  • “ansible_ssh_common_args”变量可以用于清单文件中的不同子组吗?

    我正在尝试从 2 个不同的 ProxyJumpHost 连接到 2 个主机 例如 hostname1 只能通过 ProxyJumpHost1 访问 hostname2 只能通过 ProxyJumpHost2 访问 当我为该组单独提供 ans
  • 正则表达式错误地分割:用逗号但不在方括号内(两者都是 ) 和 ] )

    正则表达式的想法 用逗号分隔 后面不跟任何字符 and 或 此外 两个括号都应该被考虑 和 假设 字符串包含有效的括号 这是我的功能 function spl str var reg w s console log str split re
  • 我的 Admob 横幅显示在顶部

    我的应用程序中有一个 admob 横幅 并且我已经使用 AdMob 提供的文档实现了它 唯一的问题是它没有显示在屏幕底部 而是显示在顶部 现在我已经寻找了很长时间但我找不到如何更改它 也找不到网络上解决此问题的任何人 有人知道如何解决这个问
  • 使用 Gstreamer 提供 RTSP 流,寻求工作示例

    我们正在尝试让 Gstreamer 在 DM368 Leopardboard 上运行 我们已成功说服它创建测试视频 videotestsrc 对其进行编码并将其转储到文件中 有效的管道是 gst launch v videotestsrc
  • 使用 AutoFac 2 避免服务定位器

    我正在构建一个使用 AutoFac 2 进行 DI 的应用程序 我去过reading http code google com p autofac wiki BestPractices应避免使用静态 IoCHelper 服务定位器 IoCH
  • 什么样的下载代码违反了App Store审核指南?

    应用商店审查指南指出 以任何方式或形式下载代码的应用程序都将被拒绝 我想制作一个使用挑战响应进行身份验证的应用程序 该应用程序拥有 SHA 1 SHA 256 MD5 DES AES 等一组基本算法 挑战服务器制作包含随机排列的算法名称数组
  • PHP 一次提供一页服务

    我正在运行 Apache 2 和 PHP 5 2 配置 由于某种原因 PHP 一次只能提供一页服务 我有两个页面最能说明问题 test1 php 和 test2 php test1 php 中只有 sleep 120 test2 php 有
  • 2015 年的 signalr 3.0 beta 是否可用?

    想要将 Signalr 代码移植到 vnext 项目中 但我没有看到 SignalR 3 x 的参考 您需要在您的包中引用该包project json文件 像这样 dependencies Microsoft AspNet SignalR
  • 鼓励 JVM 进行 GC 而不是增加堆?

    请注意 当我说 JVM 时 我真正的意思是 热点 并且我正在运行最新的 Java 1 6 更新 示例情况 我的 JVM 正在运行 Xmx 设置为 1gb 目前 堆已分配 500mb 其中 450mb 已使用 该程序需要在堆上再加载 200
  • python中的正则表达式组重复

    string input ports 6012 6017 6016 m re match input ports s d 4 s d 4 s d 4 string print m groups gt 6012 6017 6016 但是当我想
  • elasticsearch聚合按聚合比率排序

    我在分析中有一个场景 我想计算表现最差的 20 个网点在 1000 多家门店中performance transactionCount VisitCount每月在折扣店 映射是 CustomerVisit properties outlet
  • 为什么 64 位机器上会出现内存碎片问题?

    在 32 位机器中 每个进程获得 4GB 的虚拟空间 在这种情况下 人们可能会担心我们可能会因为碎片化而遇到麻烦 但对于 64 位机器 理论上我们拥有巨大的可寻址虚拟内存 那么为什么内存碎片在 64 位机器中仍然是一个问题 如果有的话 您尝
  • HTML5 模板无法在 Internet Explorer 上运行,如何解决?

    我用 HTML5 制作了一个模板 它适用于 Chrome 和 Firefox 但不适用于 Internet Explorer 在 IE 8 上测试 我怎么解决这个问题 只需将 display none 添加到您的模板中即可 适用于 11
  • asyncio 的默认调度程序什么时候公平?

    我的理解是asyncio gather旨在运行其参数同时此外 当协程执行等待表达式时 它为事件循环提供了安排其他任务的机会 考虑到这一点 我惊讶地发现以下代码片段忽略了其中一个输入asyncio gather import asyncio