当前位置:首页>python>一篇文章搞懂 Python 异步编程

一篇文章搞懂 Python 异步编程

  • 2026-10-11 07:42:46
一篇文章搞懂 Python 异步编程

写代码的人最怕什么?页面卡,用户骂,老板问。

但有时候真不是代码逻辑有问题,是你的程序在同步执行——一个任务等另一个任务,像极了食堂排队打饭,前面的人慢,后面全得等。

今天聊聊Python异步编程,帮你把这事一次搞明白。

往期阅读>>>

Python 为什么会成为AI时代的头部语言

Python 40个常用的列表推导式

Python 50个提高代码开发效率的方法

Python 自动检测服务HTTPS证书过期时间并发送预警

Python 自动化操作Redis的15个实用脚本

Python 自动化管理Jenkins的15个实用脚本,提升效率

Python copyparty搭建轻量的文件服务器的方法

Python 实现2FA认证的方法,提升安全性

Python 封装20个常用API接口,提升开发效率

App2Docker:如何无需编写Dockerfile也可以创建容器镜像

Python 集成 Nacos 配置中心的方法

Python 35个JSON数据处理方法

Python 字典与列表的20个核心技巧

Python 15个文本分析的库,提升效率

Python 15个Pandas技巧,提升数据分析效率

Python 运维中30个常用的库,提升效率

Python调用远程接口的方法

Python 提取HTML文本的方法,提升效率

Python 应用容器化方法:实现“一次部署,处处运行”

Python 自动化识别Nginx配置并导出为excel文件,提升Nginx管理效率

Python 5个常见的异步任务处理框架

Python数据科学常见的30个库

Python 50个实用代码片段,优雅高效


同步 vs 异步:排队和叫号的区别

同步代码长这样:

importrequestsdefget_data():r1 = requests.get('https://api.example.com/user/1')r2 = requests.get('https://api.example.com/user/2')r3 = requests.get('https://api.example.com/user/3')return [r1.json(), r2.json(), r3.json()]

三个请求,一个接一个执行。总耗时 = 请求1 + 请求2 + 请求3。如果每个请求200ms,光等待就要600ms。

异步代码是这样:

importasyncioimporthttpxasyncdefget_user(client, user_id):response = awaitclient.get(f'https://api.example.com/user/{user_id}')returnresponse.json()asyncdefmain():asyncwithhttpx.AsyncClient() asclient:tasks = [get_user(client, i) foriinrange(1, 4)]results = awaitasyncio.gather(*tasks)returnresults

三个请求同时发出,总耗时 ≈ 最慢那个请求的时间。200ms搞定。

差距就这么大。


核心就三个关键字:async、await、asyncio

上手异步之前,先把这三个东西搞清楚。

async 声明这个函数会“让位”——执行到这,CPU可以先去干别的。

asyncdeffetch_data():    ...

await 就是“等一等”,等另一个异步操作的结果。

result = awaitsome_async_function()

asyncio 是Python内置的异步库,提供了事件循环这些底层能力。你基本不需要直接操作它,但得 import 它:

importasyncio

就这么简单,别想复杂了。


实战:10行代码把爬虫速度拉满

光说不练假把式,上个真实场景。

我要抓取GitHub trending页面100个仓库的信息,同步写法:

importrequestsimporttimedeffetch_repos():urls = [f'https://api.github.com/repos/{i}'foriinrange(100)]results = []forurlinurls:r = requests.get(url)results.append(r.json())returnresultsstart = time.time()fetch_repos()print(f'同步耗时: {time.time() - start:.2f}s')

在我这台机器上,跑了 48秒。

换成异步:

importasyncioimporthttpximporttimeasyncdeffetch_one(client, repo_id):url = f'https://api.github.com/repos/test/repo{repo_id}'r = awaitclient.get(url)returnr.json()asyncdefmain():asyncwithhttpx.AsyncClient() asclient:tasks = [fetch_one(client, i) foriinrange(100)]results = awaitasyncio.gather(*tasks)returnresultsstart = time.time()asyncio.run(main())print(f'异步耗时: {time.time() - start:.2f}s')

异步版本只用了 3.2秒。

提速 15倍,代码就多了4行。这事你自己品。


踩过的坑,我替你踩过了

异步虽好,但有几个坑不踩不知道。

坑一:用了异步库,但函数没声明async

# 报错requests.get('https://example.com')# 正确asyncwithhttpx.AsyncClient() asclient:awaitclient.get('https://example.com')

记住:只要涉及IO操作的地方,前面都得加 await,函数前面都得加 async。

坑二:在异步函数里调用同步代码

asyncdefbad_example():# 不要这样!time.sleep(5)  # 这会阻塞整个事件循环asyncdefgood_example():# 正确做法awaitasyncio.sleep(5)  # 异步sleep,不会阻塞其他任务

同步的 time.sleep() 会把整个程序卡住,异步版本的 asyncio.sleep() 才会交出执行权。

坑三:忘记 gather 了

asyncdefwrong_way():# 顺序执行,没有并发r1 = awaitfetch(url1)r2 = awaitfetch(url2)asyncdefright_way():# 并发执行r1, r2 = awaitasyncio.gather(fetch(url1), fetch(url2))

如果你一个个 await,跟同步写法没区别。并发要靠 asyncio.gather() 或 asyncio.create_task() 来实现。

坑四:并发数没控制,直接被封IP

异步执行太快了,100个请求可能1秒内全发出去。服务器觉得你是在攻击,直接拉黑。

解决方案:加信号量控制并发数。

importasyncioimporthttpxasyncdeffetch_with_limit(semaphore, client, url):asyncwithsemaphore:returnawaitclient.get(url)asyncdefmain():semaphore = asyncio.Semaphore(5)  # 最多同时5个请求asyncwithhttpx.AsyncClient() asclient:tasks = [fetch_with_limit(semaphore, client, f'https://example.com/{i}')foriinrange(100)]awaitasyncio.gather(*tasks)

加个信号量,想快就快,想慢就慢。


什么时候用异步,什么时候别用?

异步不是万能药,用错了反而麻烦。

适合异步的场景:

  • 网络请求(爬虫、API调用)

  • 文件读写(特别是多个文件同时操作)

  • 数据库查询(连接池 + 异步驱动)

  • Web服务(FastAPI、Sanic 这类框架)

不适合异步的场景:

  • CPU密集型任务(图片处理、机器学习、加密计算)

  • 简单的一次性操作

  • 你不熟悉的代码(异步debug比同步难多了)

一个判断标准:如果你的瓶颈在IO等待,而不是CPU计算,异步大概率能帮到你。


总结一下

今天聊了几个核心点:

  • 同步代码排队执行,异步代码“叫号”并发

  • 三个关键字打天下:async、await、asyncio

  • 并发靠 gather,限流靠 Semaphore

  • 同步库(requests、time)不能直接用,要找异步替代品

  • 异步不适合CPU密集型任务

异步编程这东西,上手成本不高,但理解透需要时间。建议你找个小项目练练手,比如把之前的同步爬虫改一版。改完你会发现:原来卡你半天的那些操作,根本不是代码问题,是写法问题。


你用异步编程踩过什么坑?或者你现在有什么场景想用异步但不知道怎么写?评论区聊聊,我来帮你看看。

觉得有用就转发给身边写Python的朋友,点在看,下次聊点更硬核的。

“无他,惟手熟尔”!有需要的用起来!
------加入知识库与更多人一起学习------

https://ima.qq.com/wiki/?shareId=f2628818f0874da17b71ffa0e5e8408114e7dbad46f1745bbd1cc1365277631c

最新文章

随机文章