Python 异步编程介绍与代码示例

news2025/2/25 11:01:34

Python 异步编程介绍与代码示例

一、异步编程概述

异步编程是一种编程范式,它旨在处理那些需要等待I/O操作完成或执行耗时任务的情况。在传统的同步编程中,代码会按照顺序逐行执行,直到遇到一个耗时操作,它会阻塞程序的执行直到该操作完成。这种阻塞式的模型在某些场景下效率低下,因为代码在等待操作完成时无法执行其他任务。异步编程通过非阻塞I/O和协程(coroutine)来提高效率,使得程序在等待某些操作时能够继续执行其他任务,从而提高程序的并发性和响应性。

二、Python 异步编程基础

Python 从 3.4 版本开始引入了 asyncio 库,为异步编程提供了丰富的支持。asyncio 库包括了协程、事件循环(event loop)、任务(task)和期物(future)等关键概念。

  1. 协程(Coroutine)
    协程是一种特殊的函数,可以在执行过程中暂停和恢复。在 Python 中,协程是通过在函数定义前加上 async 关键字来创建的。协程内部可以使用 await 关键字来暂停自身的执行,等待其他协程或异步操作完成。

  2. 事件循环(Event Loop)
    事件循环是异步编程的核心,它负责调度和执行协程,确保它们按照正确的顺序执行。在 Python 中,asyncio 模块提供了事件循环的实现,开发者可以通过 asyncio.get_event_loop() 获取默认的事件循环对象,并使用它来运行协程。

  3. 任务(Task)
    任务是 asyncio 库中的一个基本概念,它表示一个异步操作。任务可以通过调用 asyncio.create_task() 函数来创建,并返回一个 Task 对象。Task 对象本质上是一个特殊的 Future 对象,它封装了协程的执行。

  4. 期物(Future)
    期物用于承载协程的执行结果。当协程开始执行时,会创建一个 Future 对象与之关联。协程执行完成后,其结果会被存储在 Future 对象中。开发者可以通过 await 关键字等待 Future 对象的结果。

三、async/await 语法

从 Python 3.5 版本开始,可以使用 asyncawait 关键字来编写异步代码。async 关键字用于定义一个协程函数,而 await 关键字用于在协程中暂停执行,等待其他协程或异步操作完成。

示例 1:简单的异步函数
import asyncio

async 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 asyncio

async 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 会等待所有传入的协程或任务完成,并返回一个包含所有结果的列表。

四、异步编程的优势
  1. 提高程序效率
    异步编程通过非阻塞I/O和并发执行多个任务,减少了程序在等待操作完成时的空闲时间,从而提高了程序的执行效率。

  2. 提高程序响应性
    在Web服务器、数据库连接等场景中,异步编程能够更快地响应客户端的请求,提升用户体验。

  3. 简化复杂逻辑
    异步编程通过协程和事件循环等机制,使得处理复杂逻辑(如回调地狱)变得更加简单和直观。

五、异步编程的注意事项

在进行Python异步编程时,需要注意以下几个方面,以确保代码的正确性、效率和可维护性:

  1. 避免阻塞操作
    异步编程的核心优势在于非阻塞I/O,因此应尽量避免在协程中执行阻塞操作。如果必须执行阻塞操作,可以通过asyncio.run_in_executor()方法将其封装在executor中执行,从而避免阻塞事件循环。

  2. 异常处理
    异步编程中的异常处理需要格外小心。由于异步操作可能在将来的某个时间点完成,因此应使用try-except语句来捕获和处理可能的异常。此外,asyncio还提供了asyncio.ensure_future()函数,可以将协程封装为Future对象,从而更方便地处理异常。

  3. 并发度控制
    通过控制并发度,可以平衡程序的性能和资源消耗。如果并发任务过多,可能会导致资源耗尽或性能下降。可以使用asyncio.Semaphore等同步原语来限制同时执行的任务数量,从而避免这种情况的发生。

  4. 共享资源访问
    在异步编程中,多个协程可能会同时访问共享资源,这可能导致数据竞争和状态不一致的问题。为了避免这种情况,应使用适当的同步机制(如锁、信号量等)来保护共享资源。

  5. 事件循环的管理
    在Python的异步编程中,事件循环是核心组件。它负责调度和执行协程,以及处理I/O和系统事件。通常,应使用asyncio.run()函数来启动和管理事件循环,因为它会自动创建事件循环、运行协程并关闭事件循环。除非有特定需求,否则应避免手动创建和管理事件循环。

  6. 协程的调度和取消
    在复杂的异步程序中,可能需要动态地调度和取消协程。asyncio提供了asyncio.create_task()函数来创建任务(即协程的封装),并提供了任务对象的方法来检查任务状态、取消任务等。

  7. 调试和日志记录
    异步编程的调试可能比同步编程更复杂,因为程序的执行流程是非线性的。因此,应使用适当的调试工具和日志记录来跟踪程序的执行和定位问题。

  8. 第三方库和框架的兼容性
    在使用异步编程时,可能会遇到与第三方库和框架的兼容性问题。一些库可能不支持异步操作,或者它们的异步API不够完善。在这种情况下,需要仔细评估是否可以使用这些库,或者寻找替代方案。

  9. 性能优化
    异步编程虽然可以提高程序的并发性和响应性,但也可能引入额外的性能开销。例如,过多的上下文切换和锁竞争都可能导致性能下降。因此,在进行异步编程时,应注意性能优化,避免不必要的开销。

  10. 代码的可读性和可维护性
    异步代码的可读性和可维护性通常比同步代码更差,因为异步逻辑更复杂且更难跟踪。因此,在编写异步代码时,应注意代码的清晰性和结构性,避免过度复杂和难以理解的代码。

通过遵循上述注意事项,可以更有效地利用Python的异步编程能力,编写出高效、可靠和可维护的异步应用程序。

六、异步编程中的错误处理

在异步编程中,错误处理是一个重要的方面。由于异步操作可能在将来的某个时间点完成,并且可能成功或失败,因此我们需要一种机制来捕获和处理这些错误。

示例 3:异步错误处理
import asyncio

async 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 asyncio

class AsyncContextManager:
    async def __aenter__(self):
        print("Entering context")
        # 初始化代码,如打开数据库连接
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print("Exiting context")
        # 清理代码,如关闭数据库连接
        return False  # 如果需要抑制异常,则返回 True

async 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 asyncio

async def async_generator():
    for i in range(5):
        await asyncio.sleep(1)  # 模拟异步操作
        yield i

async 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 的异步编程技术。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1901979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hugging face Transformers(2)—— Pipeline

Hugging Face 是一家在 NLP 和 AI 领域具有重要影响力的科技公司,他们的开源工具和社区建设为NLP研究和开发提供了强大的支持。它们拥有当前最活跃、最受关注、影响力最大的 NLP 社区,最新最强的 NLP 模型大多在这里发布和开源。该社区也提供了丰富的教程…

gptoolbox matlab工具箱cmake 调试笔记

一、问题描述 起因:在matlab中运行Offset surface of triangle mesh in matlab的时候报错: 不支持将脚本 signed_distance 作为函数执行: E:\MATLAB_File\gptoolbox\mex\signed_distance.m> 出错 offset_bunny (第 22 行) D signed_distance(BC,V,F…

Vim编辑器与Shell命令脚本

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 目录 一、Vim文本编辑器 二、编写Shell脚本 三、流程控制语句 四、计划任务服务程序 致谢 一、Vim文本编辑器 “在Linux系统中一切都是文件&am…

Java技术栈总结:kafka篇

一、# 基础知识 1、安装 部署一台ZooKeeper服务器;安装jdk;下载kafka安装包;上传安装包到kafka服务器上:/usr/local/kafka;解压缩压缩包;进入到config目录,修改server.properties配置信息: #…

绝区叁--如何在移动设备上本地运行LLM

随着大型语言模型 (LLM)(例如Llama 2和Llama 3)不断突破人工智能的界限,它们正在改变我们与周围技术的互动方式。这些模型早已集成到我们的手机中,但到目前为止,它们理解和处理请求的能力还非常有限。然而,…

2024年7月6日 (周六) 叶子游戏新闻

自动电脑内部录音器AutoAudioRecorder: 是一款免费的自动音频录制软件,可直接将电脑内部所有的声音录制成 mp3/wav 文件,包括音乐、游戏直播、网络会议、聊天通话等音频源。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《不羁联盟》制作人&…

数据库测试|Elasticsearch和ClickHouse的对决

前言 数据库作为产品架构的重要组成部分,一直是技术人员做产品选型的考虑因素之一。 ClkLog会经常遇到小伙伴问支持兼容哪几种数据库?为什么是选择ClickHouse而不是这个或那个。 由于目前市场上主流的数据库有许多,这次我们选择其中一个比较典…

【密码学】密码学体系

密码学体系是信息安全领域的基石,它主要分为两大类:对称密码体制和非对称密码体制。 一、对称密码体制(Symmetric Cryptography) 在对称密码体制中,加密和解密使用相同的密钥。这意味着发送方和接收方都必须事先拥有这…

医院产科信息化管理系统源码,智慧产科管理系统,涵盖了从孕妇到医院初次建档、历次产检、住院分娩、统计上报到产后42天全部医院服务的信息化管理。

医院产科信息化管理系统源码,智慧产科管理系统,产科专科电子病历系统 技术架构:前后端分离Java,Vue,ElementUIMySQL8.0.36 医院产科信息化管理系统,通过构建专科病例系统实现临床保健一体化,涵…

线程池理解及7个参数

定义理解 线程池其实是一种池化的技术实现,池化技术的核心思想就是实现资源的复用,避免资源的重复创建和销毁带来的性能开销。线程池可以管理一堆线程,让线程执行完任务之后不进行销毁,而是继续去处理其它线程已经提交的任务。 …

【pytorch18】Logistic Regression

回忆线性回归 for continuous:y xwbfor probability output:yσ(xwb) σ:sigmoid or logistic 线性回归是简单的线性模型,输入是x,网络参数是w和b,输出是连续的y的值 如何把它转化为分类问题?加了sigmoid函数,输出的值不再是…

springboot服务启动读取不到application.yml中的nacos.config信息

我的版本: 可以添加bootstrap.yml文件,在里面添加nacos.config的配置信息 也可以添加VM参数 -Dspring.cloud.nacos.discovery.server-addr -Dspring.cloud.nacos.config.server-addr -Dspring.cloud.nacos.config.namespace -Dspring.cloud.nacos.discov…

Java实现登录验证 -- JWT令牌实现

目录 1.实现登录验证的引出原因 2.JWT令牌2.1 使用JWT令牌时2.2 令牌的组成 3. JWT令牌(token)生成和校验3.1 引入JWT令牌的依赖3.2 使用Jar包中提供的API来实现JWT令牌的生成和校验3.3 使用JWT令牌验证登录3.4 令牌的优缺点 1.实现登录验证的引出 传统…

LeetCode刷题之搜索二维矩阵

2024 7/5 一如既往的晴天,分享几张拍的照片嘿嘿,好几天没做题了,在徘徊、踌躇、踱步。蝉鸣的有些聒噪了,栀子花花苞也都掉落啦,今天给他剪了枝,接回一楼来了。ok,做题啦! 图1、宿舍…

EDA 2023 年世界国家suicide rate排名

文章目录 前言:关于数据集列 导入模块导入数据数据预处理探索性数据分析按性别划分的自杀率 [箱线图]相关矩阵热图自杀率最高的 15 个国家变化百分比最高的 15 个国家/地区2023 年世界地图上自杀率的国家 结尾: 前言: 随着社会的不断发展和变迁,人们对于各种社会问…

154. 寻找旋转排序数组中的最小值 II(困难)

154. 寻找旋转排序数组中的最小值 II 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转:154. 寻找旋转排序数组中的最小值 II 2.详细题解 该题是153. 寻找旋转排序数组中的最小值的进阶题,在153. 寻找旋转排序数组中的最小值…

2024 年第十四届亚太数学建模竞赛(中文赛项)浅析

需要完整B题资料,请关注:“小何数模”! 本次亚太(中文赛)数学建模的赛题已正式出炉,无论是赛题难度还是认可度,该比赛都是仅次于数模国赛的独一档,可以用于国赛前的练手训练。考虑到大家解题实属不易&…

品牌推广的核心价值:作用解析与意义探讨!

在激烈的市场竞争环境之下,品牌推广已经成为企业不可缺少的一部分。不仅关乎企业的知名度,对市场份额更是起到了决定性的作用。 作为一名手工酸奶品牌的创始人,目前全国也复制了100多家门店,这篇文章,我将和大家分享品…

web学习笔记(八十)

目录 1.小程序实现微信一键登录 2. 小程序的授权流程 3.小程序配置vant库 4.小程序配置分包 5.小程序配置独立分包 6.小程序分包预下载 1.小程序实现微信一键登录 要先实现小程序一键登录首先我们需要给按钮设置一个绑定事件,然后在绑定事件内部通过wx.login…

ETAS工具导入Com Arxml修改步骤

文章目录 前言Confgen之前的更改Confgen之后的修改CANCanIfComComMEcuM修改CanNmCanSMDCMCanTp生成RTE过程报错修改DEXT-诊断文件修改Extract问题总结前言 通讯协议栈开发一般通过导入DBC实现,ETAS工具本身导入DBC也是生成arxml后执行cfggen,本文介绍直接导入客户提供的arxml…