Python异步编程:深入理解asyncio库(上)
作者:zhanglj-qiucm | 来源:互联网 | 2024-12-28 11:52
本文介绍了Python3.4版本引入的标准库asyncio,该库为异步IO提供了强大的支持。我们将探讨为什么需要asyncio,以及它如何简化并发编程的复杂性,并详细介绍其核心概念和使用方法。
### 引言 `asyncio` 是 Python 3.4 版本引入的一个标准库,旨在提供对异步 IO 的内置支持。尽管生成器和协程已经可以实现部分异步功能,但 `asyncio` 提供了一个更为全面的框架,使得开发人员能够更高效地编写并发代码。 #### 为什么需要 `asyncio` 许多开发者可能会问,既然已经有了基于生成器的协程(如 `yield` 和 `yield from`),为什么还需要 `asyncio`?这是因为 `asyncio` 不仅简化了复杂的调度逻辑,还提供了丰富的工具和接口,帮助开发者专注于业务逻辑而非底层实现细节。 就像 Django 和 Scrapy 这样的框架一样,`asyncio` 将重复性和复杂的工作封装起来,使开发者能够更轻松地构建高性能的异步应用。 #### 学习路径 在掌握了协程的基本概念后,你可能会发现不知道如何实际应用它们来实现并发。这时,`asyncio` 就显得尤为重要了。它不仅提供了一套完整的工具链,还能帮助你更好地理解和掌握协程的工作原理。 ### 核心概念 在深入学习 `asyncio` 的使用方法之前,了解以下几个关键概念是非常有帮助的: - **事件循环 (Event Loop)**:程序启动一个无限循环,程序员可以将协程注册到事件循环上。当特定事件发生时,事件循环会调用相应的协程。 - **协程 (Coroutine)**:使用 `async def` 定义的函数,调用时返回一个协程对象。协程对象需要注册到事件循环中,由事件循环负责执行。 - **Future 对象**:表示将来某个时刻完成的任务的结果。它可以与 Task 对象互换使用。 - **Task 对象**:是对协程的进一步封装,包含任务的各种状态信息。Task 是 Future 的子类,将协程与 Future 联系在一起。 - **`async`/`await` 关键字**:用于定义和挂起协程的关键字。`async` 用于定义协程,而 `await` 用于等待异步操作完成。 ### 实战演练 为了更好地理解这些概念,我们可以通过一些实例来逐步学习。 #### 创建协程对象 ```python from collections.abc import Coroutine async def hello(name): print('Hello,', name) if __name__ == '__main__': coroutine = hello("World") # 创建协程对象 print(isinstance(coroutine, Coroutine)) # 检查是否是协程类型 ``` #### 使用 `@asyncio.coroutine` 装饰器 ```python import asyncio from collections.abc import Generator, Coroutine @asyncio.coroutine def hello(): yield from asyncio.sleep(1) if __name__ == '__main__': coroutine = hello() print(isinstance(coroutine, Generator)) # True print(isinstance(coroutine, Coroutine)) # False ``` #### 协程工作流程 协程的完整工作流程包括以下步骤: 1. 定义/创建协程对象 2. 将协程转为 Task 任务 3. 定义事件循环对象容器 4. 将 Task 任务放入事件循环并触发 ```python import asyncio async def hello(name): print('Hello,', name) if __name__ == '__main__': coroutine = hello("World") # 定义协程对象 loop = asyncio.get_event_loop() # 获取事件循环 task = loop.create_task(coroutine) # 将协程转为 Task 任务 loop.run_until_complete(task) # 触发事件循环 ``` #### `await` 与 `yield` 的对比 `await` 和 `yield` 在一定程度上有相似之处,都能实现暂停的效果,但它们的功能并不完全兼容。具体来说,`await` 只能在 `async` 函数中使用,而 `yield` 则不能。 此外,`yield from` 后面可以接可迭代对象或 Future/协程对象,而 `await` 后面只能接 Future 或协程对象。 ```python import asyncio from asyncio.futures import Future async def hello(name): await asyncio.sleep(2) print('Hello,', name) if __name__ == '__main__': coroutine = hello("World") task = asyncio.ensure_future(coroutine) print(isinstance(task, Future)) # True ``` #### 绑定回调函数 异步 IO 的实现原理是在高延迟的地方挂起,等 IO 完成后再继续执行。通常情况下,后续代码的执行依赖于 IO 的返回值,这时就需要使用回调函数。 ##### 同步回调 ```python import asyncio import time async def _sleep(x): time.sleep(2) return f'暂停了{x}秒!' if __name__ == '__main__': coroutine = _sleep(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) loop.run_until_complete(task) print(f'返回结果:{task.result()}') ``` ##### 异步回调 ```python import asyncio import time async def _sleep(x): time.sleep(2) return f'暂停了{x}秒!' if __name__ == '__main__': coroutine = _sleep(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) task.add_done_callback(lambda future: print(future.result())) loop.run_until_complete(task) ``` 通过以上内容,希望你能对 `asyncio` 有一个更全面的理解,并能够在实际项目中灵活运用。
推荐阅读
Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ...
[详细]
蜡笔小新 2024-12-28 09:44:49
本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ...
[详细]
蜡笔小新 2024-12-28 04:11:47
本文详细介绍如何结合Django框架和DRF(Django REST Framework)来设计一套有效的全局异常处理系统。这套系统不仅能够妥善处理DRF引发的异常,还能兼容Django自带的admin界面异常处理逻辑。 ...
[详细]
蜡笔小新 2024-12-13 19:37:36
golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ...
[详细]
蜡笔小新 2024-12-28 13:47:52
本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ...
[详细]
蜡笔小新 2024-12-28 09:42:41
本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ...
[详细]
蜡笔小新 2024-12-27 18:51:49
本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ...
[详细]
蜡笔小新 2024-12-27 16:01:25
前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ...
[详细]
蜡笔小新 2024-12-27 15:19:01
本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ...
[详细]
蜡笔小新 2024-12-27 15:04:09
最近重新审视了新浪云平台(SAE)提供的服务,发现其已支持Python开发。本文将详细介绍如何利用Django框架构建一个简单的新浪微博应用,并分享开发过程中的关键步骤。 ...
[详细]
蜡笔小新 2024-12-26 13:36:52
本文详细介绍了如何在 Django 中配置和使用 Token 认证,并解释了 HTTP 401 和 HTTP 403 状态码的区别。通过具体的代码示例,帮助开发者理解认证机制及权限控制。 ...
[详细]
蜡笔小新 2024-12-20 15:43:37
本文档汇总了Python编程的基础与高级面试题目,涵盖语言特性、数据结构、算法以及Web开发等多个方面,旨在帮助开发者全面掌握Python核心知识。 ...
[详细]
蜡笔小新 2024-12-19 20:26:25
本文介绍如何在Django项目中集成和使用xAdmin,这是一个增强版的管理界面,提供了比Django默认admin更多的功能。文中详细描述了集成步骤及配置方法。 ...
[详细]
蜡笔小新 2024-12-17 10:14:08
本文介绍如何在Django项目中利用UpdateView更新数据后,根据主键(pk)自动重定向至对应的DetailView页面,实现流畅的用户交互体验。 ...
[详细]
蜡笔小新 2024-12-15 15:00:26
日志记录对于软件开发至关重要,特别是在调试和维护阶段。通过日志,开发者能够追踪错误源头并了解系统的运行状态。本文将探讨如何在Django框架中有效配置和使用日志记录功能。 ...
[详细]
蜡笔小新 2024-12-14 18:37:51
zhanglj-qiucm
这个家伙很懒,什么也没留下!