异步编程 asynico、async、await最佳实践
Asynico 最佳实践
术语:
- 协程(Coroutine):协程是一种支持异步操作和暂停执行的函数或代码块。使用 async 关键字定义的函数即为协程。
- 事件循环(Event Loop):事件循环是 asyncio 的核心组件,用于调度和执行协程任务。事件循环从任务队列中依次获取任务并执行,同时也负责处理 I/O 事件和定时事件。
- 任务(Task):任务是协程的包装,表示一个可被事件循环调度的异步操作。创建任务的方式是使用
asyncio.create_task()
函数。 - Future:Future 表示一个异步操作的结果。可以通过
asyncio.Future()
创建一个 Future 对象,并使用set_result()
或set_exception()
方法设置 Future 的结果或异常。 - 异步上下文管理器(Async Context Manager):异步上下文管理器是一个可用于异步上下文的对象,类似于常规的上下文管理器。异步上下文管理器需要实现
__aenter__()
和__aexit__()
方法,以提供在进入和退出异步上下文时进行操作。 - 异步迭代器(Async Iterator):异步迭代器提供了可异步遍历的功能。异步迭代器需要实现
__aiter__()
和__anext__()
方法。 - 回调(Callback):回调函数是在某个操作完成后被调用的函数。在 asyncio 中,可以使用回调函数来处理异步操作完成后的结果或异常。
- 阻塞和非阻塞:阻塞指的是在进行某个操作时,如果无法取得需要的结果,那么程序会一直等待,直到结果可用。非阻塞指的是在进行某个操作时,如果无法取得需要的结果,程序会立即返回,而不会等待结果可用。
- 并发(Concurrency)和并行(Parallelism):并发指的是多个任务同时进行,但不一定是同时执行的;并行指的是多个任务真正的同时执行。asyncio 提供了并发的支持,但并不提供直接的并行处理。
- 线程安全(Thread-Safe):线程安全指的是多线程环境下,对共享资源进行操作时不会出现不确定的结果或数据损坏。
协程与任务
协程
coroutine -- 协程
通过 async/await 语法来声明 协程 是编写 asyncio 应用的推荐方式。 例如,以下代码段会打印 "hello",等待 1 秒,再打印 "world":
asyncio.run()
函数用来运行最高层级的入口点 "main()" 函数
实现简单的协程并发 运行两个 say_after
协程:
因为是并发的运行 可能会快1 秒左右
asyncio.create_task()
函数用来并发运行作为 asyncio任务
的多个协程。
任务
在 asyncio 中,任务(Task)是一个协程对象的高级表示形式,可以通过 asyncio.create_task() 或 asyncio.ensure_future() 来创建任务。任务会被自动调度,可以由事件循环(Event Loop)来调用和并发执行。
下面是一个简单的示例,展示了如何创建和调用一个任务:
可等待对象
如果一个对象可以在 await
语句中使用,那么它就是 可等待 对象。许多 asyncio API 都被设计为接受可等待对象。
可等待 对象有三种主要类型: 协程, 任务 和 Future.
协程
Python 协程属于 可等待 对象,因此可以在其他协程中被等待:
重要
在本文档中 "协程" 可用来表示两个紧密关联的概念:
- 协程函数: 定义形式为
async def
的函数; - 协程对象: 调用 协程函数 所返回的对象。
任务
任务 被用来“并行的”调度协程
当一个协程通过 asyncio.create_task()
等函数被封装为一个 任务,该协程会被自动调度执行:
Futures
Future
是一种特殊的 低层级 可等待对象,表示一个异步操作的 最终结果。
当一个 Future 对象 被等待,这意味着协程将保持等待直到该 Future 对象在其他地方操作完毕。
在 asyncio 中需要 Future 对象以便允许通过 async/await 使用基于回调的代码。
通常情况下 没有必要 在应用层级的代码中创建 Future 对象。
Future 对象有时会由库和某些 asyncio API 暴露给用户,用作可等待对象:
一个很好的返回对象的低层级函数的示例是 loop.run_in_executor()
创建任务
asyncio.create_task(coro, ***, name=None, context=None)
将 coro 协程 封装为一个 Task
并调度其执行。返回 Task 对象。name 不为 None
,它将使用 Task.set_name()
来设为任务的名称。
休眠
coroutine asyncio.sleep(delay, result=None)
阻塞 delay 指定的秒数。
如果指定了 result,则当协程完成时将其返回给调用者。sleep()
总是会挂起当前任务,以允许其他任务运行。将 delay 设为 0 将提供一个经优化的路径以允许其他任务运行。 这可供长期间运行的函数使用以避免在函数调用的全过程中阻塞事件循环。
以下协程示例运行 5 秒,每秒显示一次当前日期:
asyncio.get_running_loop() 获取当前的协程循环
并发运行任务
awaitable asyncio.gather(**aws*, *return_exceptions=False)
并发 运行 aws 序列中的 可等待对象。
如果 aws 中的某个可等待对象为协程,它将自动被作为一个任务调度。
如果所有可等待对象都成功完成,结果将是一个由所有返回值聚合而成的列表。结果值的顺序与 aws 中可等待对象的顺序一致。
如果 return_exceptions 为 False
(默认),所引发的首个异常会立即传播给等待 gather()
的任务。aws 序列中的其他可等待对象 不会被取消 并将继续运行。
如果 return_exceptions 为 True
,异常会和成功的结果一样处理,并聚合至结果列表。
如果 gather()
被取消,所有被提交 (尚未完成) 的可等待对象也会 被取消。
如果 aws 序列中的任一 Task 或 Future 对象 被取消,它将被当作引发了 CancelledError
一样处理 -- 在此情况下 gather()
调用 不会 被取消。这是为了防止一个已提交的 Task/Future 被取消导致其他 Tasks/Future 也被取消。
屏蔽取消操作
-
awaitable asyncio.shield(aw)
保护一个 可等待对象 防止其被
取消
。如果 aw 是一个协程,它将自动被作为任务调度。以下语句:task = asyncio.create_task(something()) res = await shield(task)
相当于:
res = await something()
超时
coroutine asyncio.timeout(delay)
其他
使用异步函数:Asynico是为了处理异步操作而设计的,因此使用异步函数而不是同步函数是最佳实践之一。使用async关键字将函数定义为异步函数,并使用await关键字来等待异步操作的结果。
示例:
使用事件循环(Event Loop):Asynico通过事件循环来调度和协调异步操作。使用asyncio.get_event_loop()来获取默认的事件循环,然后使用loop.run_until_complete()来运行异步函数。
示例:
并发执行多个异步任务:Asynico提供了asyncio.gather()函数,用于并发执行多个异步任务。该函数接受多个异步函数作为参数,并返回一个协程对象。
示例:
使用异步上下文管理器:Asynico提供了async with语法来使用异步上下文管理器,类似于使用with语法的同步上下文管理器。异步上下文管理器允许在进入和离开上下文时执行异步操作。
示例:
这些是使用Asynico的最佳实践,可以帮助你更好地进行异步编程。请根据你的具体需求和场景进行适当的调整和使用。
__EOF__

本文链接:https://www.cnblogs.com/starkzz/p/17482593.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现