深入浅出:Python 中的异步编程与协程
引言
大家好,今天我们来聊聊 异步编程 和 协程,这是近年来编程语言领域中的热点话题之一,尤其在 Python 中,它作为一种全新的编程模型,已经成为处理 IO密集型 任务的强力工具。尽管很多人对异步编程望而却步,觉得它复杂难懂,但其实掌握了它,你就能感受到异步编程带来的速度提升,尤其是在高并发、网络爬虫、爬虫框架、聊天机器人等领域,异步编程简直是神器!
所以,今天我们就从头开始,带你一步步搞懂异步编程和协程,带着你从基本概念到实际应用,通俗易懂又不失深度的讲解这项技术。
1. 什么是异步编程?
首先,来搞清楚异步编程和同步编程到底有什么区别。
-
同步编程:代码按照书写顺序逐行执行,每一行执行完,才会执行下一行。比如,你去餐厅点了菜,厨师开始做饭,直到你吃完饭才能结账离开,这个过程就叫做同步。
-
异步编程:代码执行时,不会阻塞其他任务,可以让程序在等待某些任务的结果时,去做其他事情。继续以餐厅为例,当你点了菜后,厨师开始做饭,你可以先去刷会儿手机,聊天什么的,等做完了菜再叫你吃,这个过程就叫做异步。
简单总结:同步是“做一件事等着做完”,而异步是“做事的时候,不等,去做其他事情”。如果我们把程序执行的时间浪费在等待 IO 操作(比如网络请求、数据库查询等)上,那就不如使用异步方式,让程序继续执行其他任务。
2. Python 中的异步编程
在 Python 中,异步编程通常借助 asyncio 库来实现。asyncio 是 Python 的标准库之一,专门用于写异步 I/O 代码。Python 中的异步编程主要通过 协程 来实现。
2.1 什么是协程?
在 Python 中,协程(Coroutine)是一种特殊的函数,它可以在执行过程中被暂停并在后续某个时间恢复执行。协程最常见的应用就是处理 I/O 操作(比如读取文件、发送网络请求等),因为这些操作可能需要等待一段时间,如果用同步代码,程序会一直等待,浪费了大量时间,而使用协程就能“挂起”执行并切换到其他任务。
你可以把协程想象成一个可以中途暂停并恢复的任务。这种灵活性非常适合处理大量并发 I/O 请求。
3. 如何写一个协程?
Python 使用 async 和 await 关键字来定义和执行协程。让我们先看一个简单的例子:
import asyncioasync def hello_world():print("Hello")await asyncio.sleep(1) # 模拟IO操作,暂停1秒print("World")# 运行协程
asyncio.run(hello_world())
在上面的代码中:
async def用来定义一个异步函数,也就是协程。await关键字用于在协程中调用另一个异步函数。在这个例子中,asyncio.sleep(1)会暂停协程的执行 1 秒钟,模拟一个耗时的 I/O 操作。asyncio.run()用来启动协程。
4. 让多个协程并发执行
协程的强大之处在于我们可以通过 asyncio 轻松地让多个任务并发执行。接下来,我们创建多个协程任务,让它们并行执行。
import asyncioasync def task(n):print(f"Task {n} started")await asyncio.sleep(2)print(f"Task {n} completed")async def main():# 创建多个任务并发执行tasks = [task(i) for i in range(5)]await asyncio.gather(*tasks) # 等待所有任务完成asyncio.run(main())
在上面的例子中,asyncio.gather(*tasks) 会将多个协程任务并行执行,而不是一个接一个地执行。这样,就能够在等待 I/O 操作的同时执行其他任务,充分利用时间。
5. 异步编程的优势
异步编程最明显的优势就是它能够在高并发情况下提高程序的效率,尤其在处理大量 I/O 操作时(比如网络请求、文件读写等)。
- 高效利用 CPU 资源:由于异步编程不会阻塞程序的执行,它允许 CPU 在等待 I/O 时去处理其他任务。
- 减少延迟:在传统的同步方式中,IO 操作会造成大量的延迟,而异步编程可以在等待期间执行其他任务,从而减少整体的响应时间。
- 处理大并发:使用异步编程,你可以在同一时间内启动成百上千的任务,而不会占用大量的系统资源。
6. 异步编程的陷阱
尽管异步编程非常强大,但它也有一些潜在的陷阱,尤其是当你刚接触这个概念时:
- 异步不适合所有任务:如果你的程序是 CPU 密集型的,异步编程反而可能导致性能下降。因为异步编程的优势主要体现在 I/O 密集型任务上。
- 错误处理:在异步代码中,异常的处理和同步代码有些不同,特别是在并发执行的情况下,如何捕获并处理异常需要特别注意。
- 调试困难:由于协程的执行是分散的,调试异步程序相对来说比同步程序更为复杂,尤其是在多个任务并行执行的情况下。
7. 异步与多线程的对比
很多人会问,异步编程和多线程编程有何区别。简单来说:
- 异步编程:是基于事件循环的方式,不需要多线程,适用于 I/O 密集型任务,通过非阻塞的方式提升并发度。
- 多线程编程:是通过多个线程并行执行任务,适合计算密集型任务,但也带来了线程切换的开销和数据竞争等问题。
异步编程的优势在于它能够在单个线程中高效地处理大量并发任务,而不会像多线程那样产生上下文切换的开销。
8. 实际应用案例:异步爬虫
异步编程非常适合用来写爬虫程序。假设我们需要爬取多个网页,每个网页的请求都需要花费一定的时间,如果采用同步编程,程序就会一个接一个地等待每个网页的响应,效率低下。而使用异步编程,可以让爬虫程序在等待某个网页响应时,去请求其他网页。
下面是一个简单的异步爬虫示例:
import aiohttp
import asyncioasync def fetch_url(url):async with aiohttp.ClientSession() as session:async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com', 'http://example.org', 'http://example.net']tasks = [fetch_url(url) for url in urls]results = await asyncio.gather(*tasks)for result in results:print(result[:100]) # 打印前100个字符asyncio.run(main())
在这个爬虫例子中,我们使用 aiohttp 库异步地请求多个网页,并且使用 asyncio.gather 来并行执行这些请求。这种方式比传统的同步爬虫效率更高,因为我们能够在等待网页响应时进行其他操作。
9. 总结
通过本文的讲解,我们了解了 Python 中的异步编程以及协程的基本概念、应用场景以及注意事项。异步编程在处理大量 I/O 操作时能够显著提升程序的性能,特别是在高并发的情况下,它能够更高效地利用计算机资源。不过,异步编程并不是万灵药,适合 I/O 密集型任务,但对于 CPU 密集型任务,传统的多线程或多进程编程仍然更为高效。
最后,异步编程的学习曲线可能有些陡峭,但一旦掌握了这一概念,它将为你开发高效、高性能的应用程序提供强大的支持!
相关文章:
深入浅出:Python 中的异步编程与协程
引言 大家好,今天我们来聊聊 异步编程 和 协程,这是近年来编程语言领域中的热点话题之一,尤其在 Python 中,它作为一种全新的编程模型,已经成为处理 IO密集型 任务的强力工具。尽管很多人对异步编程望而却步࿰…...
八大排序——简单选择排序
目录 1.1基本操作: 1.2动态图: 1.3代码: 代码解释 1. main 方法 2. selectSort 方法 示例运行过程 初始数组 每轮排序后的数组 最终排序结果 代码总结 1.1基本操作: 选择排序(select sorting)也…...
vue使用CSS布局技术,实现div定位到页面底部或顶部并居中功能
<template> <div > <div class"bottom-element"> 我在底部,并居中了 </div> </div> </template> 使用CSS布局技术,通过设置CSS属性来实现页面底部定位。 <style lang"scs…...
Jenkins 部署 之 Mac 一
Jenkins 部署 之 Mac 一 一.Jenkins 部署依赖 JDK 环境 查看 Mac JDK 环境,如果没有安装,先安装 打开终端输入命令:java -version Mac安装配置 JDK 二. 检查 HomeBrew 安装 检查 HomeBrew 是否安装,终端输入命令:brew -v Mac安装HomeB…...
【FastAPI 使用FastAPI和uvicorn来同时运行HTTP和HTTPS的Python应用程序】
在本文中,我们将介绍如何使用 FastAPI和uvicorn来同时运行HTTP和HTTPS的 Python应用程序。 简介 FastAPI是一个高性能的Web框架,可以用于构建快速、可靠的API。它基于Python的类型提示和异步支持,使得开发者可以轻松地编写出安全且高效的代…...
HCIA-路由器相关知识和面试问题
二、 路由器 2.1 关于路由器的知识 2.1.1 什么是路由器 路由器是一种网络层互联设备,主要用于连接多个逻辑上分开的网络,实现不同网络之间的数据路由和通信。它能根据网络层地址(如 IP 地址)来转发数据包,在网络中起…...
Docker+Jenkins自动化部署SpringBoot项目【详解git,jdk,maven,ssh配置等各种配置,附有示例+代码】
文章目录 DockerJenkins部署SpringBoot项目一.准备工作1.1安装jdk111.2安装Maven 二.Docker安装Jenkins2.1安装Docker2.2 安装Jenkins2.3进入jenkins 三.Jenkins设置3.1安装jenkins插件3.2全局工具配置全局配置jdk全局配置maven全局配置git 3.3 系统配置安装 Publish Over SSH …...
PCL 点云数学形态学操作(腐蚀)
文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 基本原理:使用结构元素(通常为滤波的窗口)的窗口模板作为处理单元,利用形态学中的膨胀与腐蚀相组合即可达到滤波的效果。 点云数据中的数学形态学运算其实和二维图像上的运算非常相似,图像上像素有x,y和亮度值…...
【设计模式】【行为型模式】观察者模式(Observer)
👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 🎵 当你的天空突…...
RAGFlow和Dify对比
RAGFlow和Dify都是基于大语言模型(LLM)的应用开发平台,具有相似的功能和应用场景,但它们在技术架构、部署要求和用户体验上存在一些差异。 RAGFlow和Dify对比 2025-02-13 22.08 RAGFlow 技术栈:RAGFlow…...
AI前端开发:蓬勃发展的机遇与挑战
人工智能(AI)领域的飞速发展,正深刻地改变着我们的生活方式,也为技术人才,特别是AI代码生成领域的专业人士,带来了前所未有的机遇。而作为AI应用与用户之间桥梁的前端开发,其重要性更是日益凸显…...
结构型模式---代理模式
概念 代理模式是一种结构型模式,主要用于在客户端和接口之间添加一个中间层,用于在客户端和接口之间进行权限控制或者其他的中间层操作。 使用场景 1、延缓初始化,当我们偶尔需要使用一个重量级的服务对象,如果一直保持该对象的…...
Java面向对象一:相关概念
面向过程&面向对象 面向过程思想 步骤清晰简单,第一步做什么,第二步做什么… 面对过程适合处理一些较为简单的问题面向对象思想 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行…...
CEF132 编译指南 MacOS 篇 - depot_tools 安装与配置 (四)
1. 引言 在 CEF132(Chromium Embedded Framework)的编译过程中,depot_tools 扮演着举足轻重的角色。这套由 Chromium 项目精心打造的脚本和工具集,专门用于获取、管理和更新 Chromium 及其相关项目(包括 CEFÿ…...
React VS Vue
React 和 Vue 是目前最流行的两个前端框架,它们在设计理念、生态系统和开发体验上各有特点。以下是对 React 和 Vue 的全方位对比: 1. 核心设计理念 React 库而非框架:React 是一个用于构建 UI 的库,专注于视图层,其…...
伺服报警的含义
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在开发C#的运动控制程序的时候,一个必要的步骤就是设置伺服报警信号的…...
CSS 属性选择器详解与实战示例
CSS 属性选择器是 CSS 中非常强大且灵活的一类选择器,它能够根据 HTML 元素的属性和值来进行精准选中。在实际开发过程中,属性选择器不仅可以提高代码的可维护性,而且能够大大优化页面的样式控制。本文将结合菜鸟教程的示例,从基础…...
基于STM32、HAL库、HS12864(ST7920,并行接口)C语言程序设计
1、hs12864.h头文件: #ifndef __HS12864_H #define __HS12864_H #ifdef __cplusplus extern "C" {#endif #include "stm32l4xx_hal.h" // 控制线定义 - 根据实际硬件修改 #define HS12864_RS_GPIO_PORT GPIOC #define HS12864_RS_PIN GPIO_PI…...
Python练习11-20
题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 题目:判断101-200之间有多少…...
探索ELK 的魅力
在大数据时代,海量日志和数据的收集、存储、处理与可视化分析变得越来越重要。而 ELK 堆栈,由 Elasticsearch、Logstash、Beats 和 Kibana 组成,正是一个强大的开源解决方案,帮助开发者和运维人员高效管理和分析日志数据。本文将详…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
