【Python 】一文吃透Python async/await!零基础入门+实战案例+流程图解[特殊字符]
一文吃透Python async/await!零基础入门+实战案例+流程图解🔥
在Python开发中,异步编程是提升程序IO效率的核心技能,而 async/await 是Python3.5+ 推出的原生异步语法糖✨,彻底简化了传统协程的复杂写法。
很多小伙伴分不清同步、异步、协程的区别,写不懂async/await的执行逻辑。今天这篇文章,从零到实战带你彻底搞懂,看完直接上手写异步代码!
一、先搞懂:为什么要用 async/await?🤔
1.1 同步代码的痛点
普通同步代码是串行执行的:上一行代码阻塞等待完成,才会执行下一行。遇到IO操作(网络请求、文件读写、数据库查询)时,CPU会闲置等待,极大浪费性能。
举个例子:批量请求10个网页,同步方式需要逐个等待,总耗时是所有请求耗时之和。
1.2 异步代码的优势
异步协程的核心:遇到IO阻塞不等待,切换去执行其他任务🚀,最大化利用CPU时间,大幅提升IO密集型程序的运行效率。
而 async/await 就是Python官方推荐的、最简洁的异步协程写法,替代了老旧的 yield、asyncio.coroutine 语法。
二、核心概念:3个关键词彻底理解💡
想要用好异步,先记住3个核心定义,简单易懂,无晦涩术语!
2.1 async:定义协程函数
在普通函数前加 async 关键字,这个函数就变成了协程函数。
特性:调用协程函数,不会立即执行函数内部代码,只会返回一个协程对象,需要放入事件循环才能执行。
# 定义协程函数
async def demo():
print("这是一个协程函数")
# 调用函数,返回协程对象,不执行内部代码
print(demo()) # 输出:<coroutine object demo at 0x...>
2.2 await:阻塞等待+任务切换
await 是异步代码的核心开关,只能写在 async 函数内部!
作用:等待IO操作完成,在等待期间让出CPU,执行其他就绪任务。
可等待对象:协程对象、Task任务、Future对象(日常开发只需关注前两者)。
简单总结:遇到await就暂停,IO等待时切任务,等待结束再恢复。
2.3 事件循环(Event Loop)
事件循环是异步程序的调度中心🎯,相当于任务管家:
-
接收所有协程任务
-
监听任务状态(阻塞/就绪)
-
自动切换、调度任务执行
所有async/await代码,必须依托事件循环才能运行。Python3.7+ 提供了极简入口:asyncio.run(),自动创建、关闭事件循环。
三、异步执行流程图解📊
用一张流程图看懂async/await完整执行逻辑,告别逻辑混乱!
3个任务,每个等待2秒,总耗时6秒,完全串行阻塞。
4.2 异步基础代码(初步提速)
注意:异步等待必须用 asyncio.sleep(),不能用普通 time.sleep()(普通睡眠会阻塞整个循环)
import asyncio
import time
# 定义异步任务
async def task(name):
print(f"任务{name} 开始执行")
await asyncio.sleep(2) # 异步IO等待,不阻塞,让出CPU
print(f"任务{name} 执行完成")
async def main():
# 逐个执行协程(注意:这不是并发!)
await task("A")
await task("B")
await task("C")
if __name__ == "__main__":
start = time.time()
asyncio.run(main()) # 启动事件循环
end = time.time()
print(f"总耗时:{end - start:.2f}s")
# 输出结果
# 任务A 开始执行
# 任务A 执行完成
# 任务B 开始执行
# 任务B 执行完成
# 任务C 开始执行
# 任务C 执行完成
# 总耗时:6.00s
这里总耗时还是6秒!重点避坑:单纯await串行调用,只是异步函数写法,没有实现并发!
4.3 真正的异步并发(核心用法🔥)
想要实现多任务并发,必须将协程封装为Task任务,交给事件循环统一调度,使用asyncio.gather() 批量执行!
import asyncio
import time
async def task(name):
print(f"任务{name} 开始执行")
await asyncio.sleep(2) # 异步阻塞,切换其他任务
print(f"任务{name} 执行完成")
async def main():
# 创建多个并发任务
tasks = [task("A"), task("B"), task("C")]
# 批量执行所有任务,实现并发
await asyncio.gather(*tasks)
if __name__ == "__main__":
start = time.time()
asyncio.run(main())
end = time.time()
print(f"总耗时:{end - start:.2f}s")
# 输出结果
# 任务A 开始执行
# 任务B 开始执行
# 任务C 开始执行
# 任务A 执行完成
# 任务B 执行完成
# 任务C 执行完成
# 总耗时:2.00s
✅ 质变!3个任务并发执行,总耗时仅2秒,效率提升3倍!这就是异步的核心魅力。
五、进阶实战:异步网络请求(爬虫必备)🌐
日常开发最常用的场景:异步批量网络请求,替代同步requests,大幅提升爬虫、接口请求效率。
异步请求需要使用 aiohttp 库(需提前安装:pip install aiohttp)
import asyncio
import aiohttp
import time
# 异步请求函数
async def fetch_url(session, url):
print(f"正在请求:{url}")
async with session.get(url) as response:
text = await response.text()
print(f"请求完成:{url},响应长度:{len(text)}")
return len(text)
async def main():
# 批量请求地址
urls = [
"https://www.baidu.com",
"https://www.qq.com",
"https://www.csdn.net"
]
# 创建异步会话
async with aiohttp.ClientSession() as session:
# 封装任务
tasks = [fetch_url(session, url) for url in urls]
# 并发执行
await asyncio.gather(*tasks)
if __name__ == "__main__":
start = time.time()
asyncio.run(main())
end = time.time()
print(f"异步请求总耗时:{end - start:.2f}s")
运行结果:多个网址同时发起请求,无需逐个等待,极大缩短批量请求耗时。
六、核心避坑指南⚠️(新手必看)
很多人写不好异步代码,都是踩了这几个坑!
6.1 禁止在async函数中使用同步阻塞方法
不要在异步函数中用 time.sleep()、同步请求、文件读写等同步操作,会阻塞整个事件循环!
✅ 正确:异步场景用 asyncio.sleep()、aiohttp、异步文件操作
6.2 await 不能单独使用
await 必须嵌套在 async def 函数内,普通函数、全局作用域直接报语法错误。
6.4 协程必须交给事件循环执行
直接调用协程函数(如 task())不会执行代码,必须通过 asyncio.run() 或 gather 提交给事件循环。
6.5 异步只适合IO密集型场景
-
✅ 适合:网络请求、文件读写、数据库操作、等待延时(IO密集型)
-
❌ 不适合:数值计算、数据处理(CPU密集型),此时异步无提升,推荐多进程
七、核心知识点总结📝
| 关键字 | 作用 | 使用场景 |
|---|---|---|
| async | 定义协程函数 | 声明所有异步函数 |
| await | 等待IO、切换任务 |
async函数内部,修饰可等待对象 |
| asyncio.gather | 批量并发执行任务 | 多任务异步并发核心 |
| asyncio.run | 启动事件循环 | Python3.7+ 程序入口 |
八、写在最后✨
async/await 是Python异步编程的基石,掌握它可以轻松实现高并发IO程序,在爬虫、接口开发、后端服务、定时任务等场景中大幅优化性能。
核心精髓就一句话:async定义异步函数,await卡点切任务,gather实现多并发!
更多推荐
所有评论(0)