Python 异之如何同时运行多个协程详解
作者:冷冻工厂 发布时间:2023-11-27 12:47:23
asyncio 的一个好处是我们可以同时运行许多协程。这些协同程序可以在一个组中创建并存储,然后同时一起执行。这可以使用 asyncio.gather() 函数来实现。
让我们仔细看看。
1. 什么是 Asyncio gather()
asyncio.gather() 模块函数允许调用者将多个可等待对象组合在一起。分组后,可等待对象可以并发执行、等待和取消。
它是一个有用的实用函数,可用于分组和执行多个协程或多个任务。
...
# run a collection of awaitables
results = await asyncio.gather(coro1(), asyncio.create_task(coro2()))
在我们可能预先创建许多任务或协程然后希望一次执行它们并等待它们全部完成后再继续的情况下,我们可以使用 asyncio.gather() 函数。
这是一种可能的情况,其中需要许多类似任务的结果,例如具有不同数据的相同任务或协程。
可等待对象可以并发执行,返回结果,并且主程序可以通过使用它所依赖的结果来恢复。
gather() 函数比简单地等待任务完成更强大。它允许将一组可等待对象视为单个可等待对象。
通过 await 表达式执行并等待组中的所有可等待对象完成。
从所有分组的等待对象中获取结果,稍后通过 result() 方法检索。
要通过 cancel() 方法取消的一组等待对象。
通过 done() 方法检查组中的所有可等待对象是否已完成。
仅当组中的所有任务完成时才执行回调函数。
2. 如何使用 Asyncio gather()
在本节中,我们将仔细研究如何使用 asyncio.gather() 函数。
asyncio.gather() 函数将一个或多个可等待对象作为参数。回想一下,可等待对象可能是协程、Future 或 Task。
因此,我们可以调用 gather() 函数:
多项任务
多个协程
任务和协程的混合
...
# execute multiple coroutines
asyncio.gather(coro1(), coro2())
如果 Task 对象被提供给 gather(),它们将已经在运行,因为 Tasks 被安排为创建的一部分。asyncio.gather() 函数将可等待对象作为位置参数。
我们不能创建可等待对象的列表或集合并将其提供给收集,因为这会导致错误。
...
# cannot provide a list of awaitables directly
asyncio.gather([coro1(), coro2()])
如果首先使用星号运算符 (*) 将其解压缩到单独的表达式中,则可以提供等待列表。
...
# gather with an unpacked list of awaitables
asyncio.gather(*[coro1(), coro2()])
如果协程提供给 gather(),它们会自动包装在 Task 对象中。gather() 函数不会阻塞。
相反,它返回一个代表可等待对象组的 asyncio.Future 对象。
...
# get a future that represents multiple awaitables
group = asyncio.gather(coro1(), coro2())
一旦创建了 Future 对象,它就会在事件循环中自动调度。awaitable 代表组,组中的所有 awaitable 都会尽快执行。这意味着如果调用者什么都不做,那么预定的可等待对象组将运行(假设调用者挂起)。
这也意味着您不必等待从 gather() 返回的 Future。
...
# get a future that represents multiple awaitables
group = asyncio.gather(coro1(), coro2())
# suspend and wait a while, the group may be executing..
await asyncio.sleep(10)
可以等待返回的 Future 对象,它将等待组中的所有可等待对象完成。
...
# run the group of awaitables
await group
等待从 gather() 返回的 Future 将返回可等待对象的返回值列表。
如果可等待对象没有返回值,则此列表将包含默认的“无”返回值。
...
# run the group of awaitables and get return values
results = await group
这通常在一行中执行。
...
# run tasks and get results on one line
results = await asyncio.gather(coro1(), coro2())
3. 列表中多个协程的 gather() 示例
预先创建多个协程然后再收集它们是很常见的。这允许程序准备要并发执行的任务,然后立即触发它们的并发执行并等待它们完成。
我们可以手动或使用列表理解将许多协程收集到一个列表中。
...
# create many coroutines
coros = [task_coro(i) for i in range(10)]
然后我们可以用列表中的所有协程调用 gather()。协程列表不能直接提供给 gather() 函数,因为这会导致错误。相反,gather() 函数要求将每个可等待对象作为单独的位置参数提供。
这可以通过将列表展开为单独的表达式并将它们传递给 gather() 函数来实现。星号运算符 (*) 将为我们执行此操作。
...
# run the tasks
await asyncio.gather(*coros)
将它们结合在一起,下面列出了使用 gather() 运行预先准备好的协程列表的完整示例。
# SuperFastPython.com
# example of gather for many coroutines in a list
import asyncio
# coroutine used for a task
async def task_coro(value):
# report a message
print(f'>task {value} executing')
# sleep for a moment
await asyncio.sleep(1)
# coroutine used for the entry point
async def main():
# report a message
print('main starting')
# create many coroutines
coros = [task_coro(i) for i in range(10)]
# run the tasks
await asyncio.gather(*coros)
# report a message
print('main done')
# start the asyncio program
asyncio.run(main())
运行该示例会执行 main() 协程作为程序的入口点。main() 协程然后使用列表理解创建一个包含 10 个协程对象的列表。然后将此列表提供给 gather() 函数,并使用星号运算符将其解压缩为 10 个单独的表达式。
然后 main() 协程等待从调用 gather() 返回的 Future 对象,暂停并等待所有调度的协程完成它们的执行。协程会尽快运行,报告它们独特的消息并在终止前休眠。
只有在组中的所有协程都完成后,main() 协程才会恢复并报告其最终消息。这突出了我们如何准备协程集合并将它们作为单独的表达式提供给 gather() 函数。
main starting
>task 0 executing
>task 1 executing
>task 2 executing
>task 3 executing
>task 4 executing
>task 5 executing
>task 6 executing
>task 7 executing
>task 8 executing
>task 9 executing
main done
来源:https://juejin.cn/post/7201838656894468155


猜你喜欢
- //1、运行到C盘根目录 //2、输入:SET ORACLE_SID = 你的SID名称 3、输入:sqlplus/nolog 4、输入:c
- 范围选区概述范围选区是一种常见的对象选择方式,在一个子图中,可以在某一个轴方向上用鼠标选择起始范围的数据,这个特性可用来实现数据缩放(dat
- 如何进行 Python 性能优化,是本文探讨的主要问题。本文会涉及常见的代码优化方法,性能优化工具的使用以及如何诊断代码的性能瓶颈等内容,希
- 本文实例讲述了Python闭包实现计数器的方法。分享给大家供大家参考。具体实现方法如下:先来看看专业的解释:闭包(Closure)是词法闭包
- 介绍这个例子主要利用turtle库实现根据输入动态展示不同机器人的图像和属性信息。代码部分非原创只是做了些许修改和整理使得更易阅读。图片和文
- 事情是这样的:平时我汇报或者写论文需要画图,都会喜欢用Python的 matplotlib 和 seaborn 把数据📊 📈 和分析结果 🗂
- Base64编码的深入认识与理解 之前在很多业务中都有见过或者用到过Base64编码,但一直一知半解,没有对它有一个深入的认识和
- 用Python基于Google Bard做一个交互式的聊天机器人之前已经通过浏览器试过了 Google Bard ,更多细节请看: Try
- 许多人也许会注意到一个现象,那就是在一些现代编程语言(当然,并不是指“最近出现”的编程语言)中,自增
- 使用Python时,常遇到的一个问题就是Python和库的版本不同。Anaconda的env算是解决这个问题的一个好用的方法。但是,在使用J
- enumerate首先介绍的是enumerate函数。在我们日常编程的过程当中,经常会遇到一个问题。在C语言以及一些古老的语言当中是没有迭代
- 查询缓存1.查询缓存操作原理mysql执行查询语句之前,把查询语句同查询缓存中的语句进行比较,且是按字节比较,仅完全一致才被认为相同。如下,
- 本文实例总结了javascript设置文本框光标的方法。分享给大家供大家参考,具体如下:对于text//得到光标位置function get
- 本文实例为大家分享了js实现QQ邮箱邮件拖拽删除的具体代码,供大家参考,具体内容如下步骤分析:根据数据结构生成HTML结构全选和单选功能的实
- function gaga(obj){ // 值允许输入一个小数点和数字 obj.value = obj.value.replace(/[^
- ⛳️ 实战场景本篇博客为大家再次带来 Go 语言的基础知识,这次要学习的内容是 Go 中的文件操作。打开关闭文件在 Go 中操作文件,首先要
- 发现一个有意思的现象,labelimg打开图片和xml标签时候,看不到标注好的框框,仔细查看了xml文件,没发现什么异常,后面试一下,才发现
- 一、前言这篇文章,我们将会尝试从零搭建一个简单的新闻搜索引擎当然,一个完整的搜索引擎十分复杂,这里我们只介绍其中最为核心的几个模块分别是数据
- 如下所示:#-*- coding: utf-8 -*-import pandas as pdimport numpy as npfrom p
- 概述运行python脚本时通过命令行方式传入运行参数通常有以下两种自建方式:sys.argv - 简洁argparse - 丰富,可自定义下