Python 异步: 同时运行多个协程(10)

简介: 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
相关文章
|
1天前
|
Rust JavaScript 前端开发
[oeasy]python075_什么是_动态类型_静态类型_强类型_弱类型_编译_运行
本文探讨了编程语言中的动态类型与静态类型、强类型与弱类型的概念。通过实例分析,如Python允许变量类型动态变化(如`age`从整型变为字符串),而C语言一旦声明变量类型则不可更改,体现了动态与静态类型的差异。此外,文章还对比了强类型(如Python,不允许隐式类型转换)和弱类型(如JavaScript,支持自动类型转换)的特点。最后总结指出,Python属于动态类型、强类型语言,对初学者友好但需注意类型混淆,并预告下期内容及提供学习资源链接。
37 21
|
2月前
|
人工智能 开发者 Python
Chainlit:一个开源的异步Python框架,快速构建生产级对话式 AI 应用
Chainlit 是一个开源的异步 Python 框架,帮助开发者在几分钟内构建可扩展的对话式 AI 或代理应用,支持多种工具和服务集成。
281 9
|
2月前
|
Python
深入理解 Python 中的异步操作:async 和 await
Python 的异步编程通过 `async` 和 `await` 关键字处理 I/O 密集型任务,如网络请求和文件读写,显著提高性能。`async` 定义异步函数,返回 awaitable 对象;`await` 用于等待这些对象完成。本文介绍异步编程基础、`async` 和 `await` 的用法、常见模式(并发任务、异常处理、异步上下文管理器)及实战案例(如使用 aiohttp 进行异步网络请求),帮助你高效利用系统资源并提升程序性能。
114 7
|
2月前
|
SQL 网络协议 安全
Python异步: 什么时候使用异步?
Asyncio 是 Python 中用于异步编程的库,适用于协程、非阻塞 I/O 和异步任务。使用 Asyncio 的原因包括:1) 使用协程实现轻量级并发;2) 采用异步编程范式提高效率;3) 实现非阻塞 I/O 提升 I/O 密集型应用性能。然而,Asyncio 并不适合所有场景,特别是在 CPU 密集型任务或已有线程/进程方案的情况下。选择 Asyncio 应基于项目需求和技术优势。
|
3月前
|
数据挖掘 vr&ar C++
让UE自动运行Python脚本:实现与实例解析
本文介绍如何配置Unreal Engine(UE)以自动运行Python脚本,提高开发效率。通过安装Python、配置UE环境及使用第三方插件,实现Python与UE的集成。结合蓝图和C++示例,展示自动化任务处理、关卡生成及数据分析等应用场景。
260 5
|
3月前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
98 3
|
4月前
|
开发者 Python
使用Python实现自动化邮件通知:当长时程序运行结束时
本文介绍了如何使用Python实现自动化邮件通知功能,当长时间运行的程序完成后自动发送邮件通知。主要内容包括:项目背景、设置SMTP服务、编写邮件发送函数、连接SMTP服务器、发送邮件及异常处理等步骤。通过这些步骤,可以有效提高工作效率,避免长时间等待程序结果。
148 9
|
3月前
|
Shell 开发工具 Python
如何在vim里直接运行python程序
如何在vim里直接运行python程序
|
9月前
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
85 1
使用python实现一个用户态协程
|
6月前
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
60 0

热门文章

最新文章