Python 异步编程介绍与代码示例
Python 异步编程介绍与代码示例
一、异步编程概述
异步编程是一种编程范式,它旨在处理那些需要等待I/O操作完成或执行耗时任务的情况。在传统的同步编程中,代码会按照顺序逐行执行,直到遇到一个耗时操作,它会阻塞程序的执行直到该操作完成。这种阻塞式的模型在某些场景下效率低下,因为代码在等待操作完成时无法执行其他任务。异步编程通过非阻塞I/O和协程(coroutine)来提高效率,使得程序在等待某些操作时能够继续执行其他任务,从而提高程序的并发性和响应性。
二、Python 异步编程基础
Python 从 3.4 版本开始引入了 asyncio 库,为异步编程提供了丰富的支持。asyncio 库包括了协程、事件循环(event loop)、任务(task)和期物(future)等关键概念。
-
协程(Coroutine):
协程是一种特殊的函数,可以在执行过程中暂停和恢复。在 Python 中,协程是通过在函数定义前加上async关键字来创建的。协程内部可以使用await关键字来暂停自身的执行,等待其他协程或异步操作完成。 -
事件循环(Event Loop):
事件循环是异步编程的核心,它负责调度和执行协程,确保它们按照正确的顺序执行。在 Python 中,asyncio模块提供了事件循环的实现,开发者可以通过asyncio.get_event_loop()获取默认的事件循环对象,并使用它来运行协程。 -
任务(Task):
任务是asyncio库中的一个基本概念,它表示一个异步操作。任务可以通过调用asyncio.create_task()函数来创建,并返回一个Task对象。Task对象本质上是一个特殊的Future对象,它封装了协程的执行。 -
期物(Future):
期物用于承载协程的执行结果。当协程开始执行时,会创建一个Future对象与之关联。协程执行完成后,其结果会被存储在Future对象中。开发者可以通过await关键字等待Future对象的结果。
三、async/await 语法
从 Python 3.5 版本开始,可以使用 async 和 await 关键字来编写异步代码。async 关键字用于定义一个协程函数,而 await 关键字用于在协程中暂停执行,等待其他协程或异步操作完成。
示例 1:简单的异步函数
import asyncioasync def my_coroutine():print("Coroutine started")await asyncio.sleep(1) # 模拟异步操作print("Coroutine resumed")return "Result"async def main():result = await my_coroutine()print(f"Result: {result}")asyncio.run(main())
在这个示例中,my_coroutine 是一个协程函数,它使用 await asyncio.sleep(1) 来模拟一个耗时操作。main 函数也是一个协程函数,它使用 await 关键字等待 my_coroutine 的执行结果。最后,通过 asyncio.run(main()) 启动事件循环,并运行 main 协程。
示例 2:并发执行多个异步任务
import asyncioasync def task(name, delay):print(f"Executing task: {name}")await asyncio.sleep(delay)print(f"Task {name} finished")async def main():tasks = [task("Task 1", 2), task("Task 2", 1), task("Task 3", 3)]await asyncio.gather(*tasks)asyncio.run(main())
在这个示例中,我们定义了三个异步任务 task,每个任务都有一个名称和延迟时间。在 main 函数中,我们使用 asyncio.gather(*tasks) 来并发执行这些任务。asyncio.gather 会等待所有传入的协程或任务完成,并返回一个包含所有结果的列表。
四、异步编程的优势
-
提高程序效率:
异步编程通过非阻塞I/O和并发执行多个任务,减少了程序在等待操作完成时的空闲时间,从而提高了程序的执行效率。 -
提高程序响应性:
在Web服务器、数据库连接等场景中,异步编程能够更快地响应客户端的请求,提升用户体验。 -
简化复杂逻辑:
异步编程通过协程和事件循环等机制,使得处理复杂逻辑(如回调地狱)变得更加简单和直观。
五、异步编程的注意事项
在进行Python异步编程时,需要注意以下几个方面,以确保代码的正确性、效率和可维护性:
-
避免阻塞操作:
异步编程的核心优势在于非阻塞I/O,因此应尽量避免在协程中执行阻塞操作。如果必须执行阻塞操作,可以通过asyncio.run_in_executor()方法将其封装在executor中执行,从而避免阻塞事件循环。 -
异常处理:
异步编程中的异常处理需要格外小心。由于异步操作可能在将来的某个时间点完成,因此应使用try-except语句来捕获和处理可能的异常。此外,asyncio还提供了asyncio.ensure_future()函数,可以将协程封装为Future对象,从而更方便地处理异常。 -
并发度控制:
通过控制并发度,可以平衡程序的性能和资源消耗。如果并发任务过多,可能会导致资源耗尽或性能下降。可以使用asyncio.Semaphore等同步原语来限制同时执行的任务数量,从而避免这种情况的发生。 -
共享资源访问:
在异步编程中,多个协程可能会同时访问共享资源,这可能导致数据竞争和状态不一致的问题。为了避免这种情况,应使用适当的同步机制(如锁、信号量等)来保护共享资源。 -
事件循环的管理:
在Python的异步编程中,事件循环是核心组件。它负责调度和执行协程,以及处理I/O和系统事件。通常,应使用asyncio.run()函数来启动和管理事件循环,因为它会自动创建事件循环、运行协程并关闭事件循环。除非有特定需求,否则应避免手动创建和管理事件循环。 -
协程的调度和取消:
在复杂的异步程序中,可能需要动态地调度和取消协程。asyncio提供了asyncio.create_task()函数来创建任务(即协程的封装),并提供了任务对象的方法来检查任务状态、取消任务等。 -
调试和日志记录:
异步编程的调试可能比同步编程更复杂,因为程序的执行流程是非线性的。因此,应使用适当的调试工具和日志记录来跟踪程序的执行和定位问题。 -
第三方库和框架的兼容性:
在使用异步编程时,可能会遇到与第三方库和框架的兼容性问题。一些库可能不支持异步操作,或者它们的异步API不够完善。在这种情况下,需要仔细评估是否可以使用这些库,或者寻找替代方案。 -
性能优化:
异步编程虽然可以提高程序的并发性和响应性,但也可能引入额外的性能开销。例如,过多的上下文切换和锁竞争都可能导致性能下降。因此,在进行异步编程时,应注意性能优化,避免不必要的开销。 -
代码的可读性和可维护性:
异步代码的可读性和可维护性通常比同步代码更差,因为异步逻辑更复杂且更难跟踪。因此,在编写异步代码时,应注意代码的清晰性和结构性,避免过度复杂和难以理解的代码。
通过遵循上述注意事项,可以更有效地利用Python的异步编程能力,编写出高效、可靠和可维护的异步应用程序。
六、异步编程中的错误处理
在异步编程中,错误处理是一个重要的方面。由于异步操作可能在将来的某个时间点完成,并且可能成功或失败,因此我们需要一种机制来捕获和处理这些错误。
示例 3:异步错误处理
import asyncioasync def risky_operation():# 假设这是一个可能引发异常的异步操作await asyncio.sleep(1)raise ValueError("Something went wrong!")async def main():try:await risky_operation()except ValueError as e:print(f"Caught an exception: {e}")asyncio.run(main())
在这个示例中,risky_operation 是一个可能抛出异常的异步函数。在 main 函数中,我们使用 try-except 块来捕获并处理这个异常。
七、异步上下文管理器
在 Python 中,上下文管理器(通过 with 语句使用)常用于资源管理,如文件操作、数据库连接等。在异步编程中,我们也有异步上下文管理器的需求。
从 Python 3.7 开始,asyncio 库引入了 async with 语法,允许我们使用异步上下文管理器。
示例 4:异步上下文管理器
import asyncioclass AsyncContextManager:async def __aenter__(self):print("Entering context")# 初始化代码,如打开数据库连接return selfasync def __aexit__(self, exc_type, exc_val, exc_tb):print("Exiting context")# 清理代码,如关闭数据库连接return False # 如果需要抑制异常,则返回 Trueasync def main():async with AsyncContextManager():print("Inside the context")await asyncio.sleep(1)asyncio.run(main())
在这个示例中,AsyncContextManager 类定义了异步上下文管理器的行为。__aenter__ 方法在进入上下文时执行,__aexit__ 方法在退出上下文时执行。注意,__aexit__ 方法必须返回一个布尔值,用于指示是否需要抑制异常。
八、异步编程与并发
虽然异步编程和并发编程经常一起讨论,但它们并不完全相同。异步编程主要关注于单个线程内的非阻塞操作,而并发编程则涉及多个线程或进程同时执行多个任务。然而,在 Python 的 asyncio 库中,我们可以通过异步编程实现并发效果,因为事件循环能够同时调度多个协程的执行。
九、高级话题:异步生成器
Python 3.6 引入了异步生成器(async generators),它们是结合了异步编程和生成器特性的强大工具。异步生成器允许你编写一个可以异步产生值的函数,这些值可以在需要时逐个获取,而无需一次性加载到内存中。
示例 5:异步生成器
import asyncioasync def async_generator():for i in range(5):await asyncio.sleep(1) # 模拟异步操作yield iasync def main():async for value in async_generator():print(value)asyncio.run(main())
在这个示例中,async_generator 是一个异步生成器函数,它使用 yield 关键字来异步产生值。在 main 函数中,我们使用 async for 循环来逐个获取这些值。
十、总结
Python 的异步编程通过 asyncio 库提供了强大的支持,使得编写高效、响应迅速的异步应用程序成为可能。通过协程、事件循环、任务和期物等概念,Python 的异步编程模型能够处理复杂的异步逻辑,并优化程序的执行效率。然而,异步编程也带来了一些挑战,如错误处理和并发控制等。通过深入学习这些概念,并结合实际的应用场景,我们可以更好地利用 Python 的异步编程能力来构建高效、可靠的应用程序。
以上就是对 Python 异步编程的一个基本介绍和代码示例。希望这些信息能够帮助你理解并掌握 Python 的异步编程技术。

相关文章:
Python 异步编程介绍与代码示例
Python 异步编程介绍与代码示例 一、异步编程概述 异步编程是一种编程范式,它旨在处理那些需要等待I/O操作完成或执行耗时任务的情况。在传统的同步编程中,代码会按照顺序逐行执行,直到遇到一个耗时操作,它会阻塞程序的执行直到…...
堆叠的作用
一、为什么要堆叠 传统的园区网络采用设备和链路冗余来保证高可靠性,但其链路利用率低、网络维护成本高,堆叠技术将多台交换机虚拟成一台交换机,达到简化网络部署和降低网络维护工作量的目的。 二、堆叠优势 1、提高可靠性 堆叠系统多台成…...
ubuntu 如何查看某一个网卡的ip地址
在Ubuntu中,你可以使用多种方法来查看某一个网卡的IP地址。以下是一些常用的方法: 使用ip命令: ip命令是现代Linux系统中用于显示和操作路由、网络设备、策略路由和隧道的工具。要查看所有网络接口的IP地址,你可以使用:…...
跨界客户服务:拓展服务边界,创造更多价值
在当今这个日新月异的商业时代,跨界合作已不再是新鲜词汇,它如同一股强劲的东风,吹散了行业间的壁垒,为企业服务创新开辟了前所未有的广阔天地。特别是在客户服务领域,跨界合作正以前所未有的深度和广度,拓…...
linux驱动编程 - kfifo先进先出队列
简介: kfifo是Linux Kernel里面的一个 FIFO(先进先出)数据结构,它采用环形循环队列的数据结构来实现,提供一个无边界的字节流服务,并且使用并行无锁编程技术,即当它用于只有一个入队线程和一个出…...
JS 四舍五入使用整理
一、Number.toFixed() 把数字转换为字符串,结果的小数点后有指定位数的数字,重点返回的数据类型为字符串 toFixed() 方法将一个浮点数转换为指定小数位数的字符串表示,如果小数位数高于数字,则使用 0 来填充。 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。…...
上万组风电,光伏,用户负荷数据分享
上万组风电,光伏,用户负荷数据分享 可用于风光负荷预测等研究 获取链接🔗 https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取码:381i 获取链接🔗 https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取…...
在物联网快速发展的趋势下,Java 怎样优化对低功耗、资源受限的边缘设备的支持,保障物联网应用的稳定运行?
在物联网快速发展的趋势下,Java可以通过以下方式优化对低功耗、资源受限的边缘设备的支持,以保障物联网应用的稳定运行: 精简Java运行环境:针对边缘设备的资源限制,可以使用精简型的Java运行环境,避免不必要…...
java-HashSet 源码分析 1
## 深入分析 Java 中的 HashSet 源码 HashSet 是 Java 集合框架中的一个重要类,它基于哈希表实现,用于存储不重复的元素。HashSet 允许 null 元素,并且不保证元素的顺序。本文将详细分析 HashSet 的源码,包括其数据结构、构造方法…...
K8S 部署 EFK
安装说明 系统版本为 Centos7.9 内核版本为 6.3.5-1.el7 K8S版本为 v1.26.14 ES官网 开始安装 本次安装使用官方ECK方式部署 EFK,部署的是当前的最新版本。 在 Kubernetes 集群中部署 ECK 安装自定义资源 如果能打开这个网址的话直接用这个命令安装,打不开的话…...
AI Earth应用—— 在线使用sentinel数据VV和VH波段进行水体提取分析(昆明抚仙湖、滇池为例)
AI Earth 本文的主要目的就是对水体进行提取,这里,具体的操作步骤很简单基本上是通过,首页的数据检索,选择需要研究的区域,然后选择工具箱种的水体提取分析即可,剩下的就交给阿里云去处理,结果如下: 这是我所选取的一景影像: 详情 卫星: Sentinel-1 级别: 1 …...
基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建基于Hadoop的全分布式集群---任务9:HBase的安装和部署
任务描述 任务内容为HBase的安装部署与测试。 任务指导 HBase集群需要整个集群所有节点安装的HBase版本保持一致,并且拥有相同的配置 具体配置步骤如下: 1. 解压缩HBase的压缩包 2. 配置HBase的环境变量 3. 修改HBase的配置文件,HBase…...
go语言day09 通道 协程的死锁
Go语言学习——channel的死锁其实没那么复杂 - JackieZheng - 博客园 (cnblogs.com) 目录 通道 创建通道 1)无缓冲通道 2)有缓冲通道 通道的使用 1) 值从通道入口进 2) 值从通道出口出 信道死锁: 0)死锁现场0 1)死…...
黑马的ES课程中的不足
在我自己做项目使用ES的时候,发现了黑马没教的方法,以及一些它项目的小问题 搜索时的匹配方法 这个boolQuery().should 我的项目是通过文章的标题title和内容content来进行搜索 但是黑马它的项目只用了must 如果我们的title和content都用must&#x…...
STM32 中断编程入门
目录 一、中断系统 1、中断的原理 2、中断类型 外部中断 定时器中断 DMA中断 3、中断处理函数 中断标志位清除 中断服务程序退出 二、实际应用 中断控制LED 任务要求 代码示例 中断控制串口通信 任务要求1 代码示例 任务要求2 代码示例 总结 学习目标&…...
使用maven搭建一个SpingBoot项目
1.首先创建一个maven项目 注意选择合适的jdk版本 2.添加依赖 2.在pom.xml中至少添加依赖 spring-boot-starter-web 依赖,目的是引入Tomcat,以及SpringMVC等,使项目具有web功能。 <!-- 引入 包含tomcat,SpringMVC,…...
使用 HTTPS 已成为网站的标配了
网站使用HTTPS的原因 背景:十年前,HTTPS并不普遍,但随着网络安全意识的提高,现在已成为网站标配。 网站升级到HTTPS的动机 安全问题:HTTP缺乏安全机制,易被窃取和篡改数据。例如,电信运营商劫…...
前后端分离Nginx
背景 旧的部署方式是将前端代码打包进后端包的resource server {listen 80;listen 443 ssl;server_name xxx.test.com;location / {proxy_pass http://xxx.test.com;} }后端:https:// xxx.test.com/simcard/querySimcard 前端:https:// x…...
【简单讲解下Tauri】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
mac上挂载linux目录
在 macOS 上挂载 CentOS 目录步骤: 在挂载前确保 macOS 和 CentOS 在同一个局域网内,并且可以相互访问。如果有网络配置问题,可能会导致挂载失败或连接被拒绝的错误。 要在 macOS 上将 CentOS 的 /disk2/go 目录通过 NFS 挂载到 /Users/zon…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
