news 2026/5/10 9:18:46

Python异步性能调优实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python异步性能调优实战

Python异步性能调优实战:连接池、背压与结构化并发

asyncio不只是把函数加个async关键字。真正的异步优化在于连接池管理、背压控制和结构化并发——这三板斧用好了,性能能翻3-10倍。

前言

很多Python开发者对asyncio的理解停留在"把def换成async def,把调用加个await"。结果写出来的代码虽然"异步"了,但性能甚至不如同步版本。

我曾经接手过一个项目,前任开发者用asyncio写了一个爬虫,号称"高并发"。结果一测速,每秒只能爬20个页面——跟同步版本没什么区别。问题出在哪?连接池没配好、没有背压控制、用法全是反模式

这篇文章会从实际性能问题出发,深入讲解asyncio的三个核心优化方向:连接池、背压、结构化并发。每个点都有真实代码和性能对比。


一、asyncio基础回顾与常见误区

1.1 异步不是万能药

先说结论:asyncio适合IO密集型任务,不适合CPU密集型任务

# ❌ 错误:CPU密集任务用asyncioasyncdefcpu_heavy_task():result=0foriinrange(10_000_000):result+=i# 这是CPU计算,不会让出控制权!returnresult# 这样写只会阻塞事件循环,其他协程全部等待asyncdefmain():# 两个任务看起来是"并发"的,实际上是串行的r1=awaitcpu_heavy_task()r2=awaitcpu_heavy_task()# ✅ 正确:CPU密集任务用ProcessPoolExecutorimportasynciofromconcurrent.futuresimportProcessPoolExecutordefcpu_heavy_sync(n:int)->int:result=0foriinrange(n):result+=ireturnresultasyncdefmain():loop=asyncio.get_event_loop()withProcessPoolExecutor()aspool:# 真正的并行计算r1=loop.run_in_executor(pool,cpu_heavy_sync,10_000_000)r2=loop.run_in_executor(pool,cpu_heavy_sync,10_000_000)results=awaitasyncio.gather(r1,r2)

1.2 常见反模式

反模式1:在异步函数中调用同步阻塞代码
importtimeimportrequests# 同步HTTP库!# ❌ 错误:用了async但内部是同步阻塞的asyncdeffetch_url(url:str)->str:response=requests.get(url)# 这会阻塞整个事件循环!returnresponse.text# 后果:所有其他协程都被阻塞,变成串行执行asyncdefmain():urls=["https://api.example.com/1","https://api.example.com/2"]results=awaitasyncio.gather(*[fetch_url(u)foruinurls])# 实际执行时间 = sum(每个请求的时间),不是 max# ✅ 正确:使用异步HTTP库importaiohttpasyncdeffetch_url_async(url:str)->str:asyncwithaiohttp.ClientSession()assession:asyncwithsession.get(url)asresponse:returnawaitresponse.text()# 执行时间 = max(每个请求的时间),真正的并发
反模式2:每次请求创建新连接
# ❌ 错误:每次请求都创建新的sessionasyncdeffetch_all(urls:list[str])->list[str]:results=[]forurlinurls:asyncwithaiohttp.ClientSession()assession:# 每次都创建新连接!asyncwithsession.get(url)asresp:results.append(awaitresp.text())returnresults# 问题:创建TCP连接有开销(DNS解析、TCP握手、TLS握手)# 100个URL = 100次完整连接建立# ✅ 正确:复用sessionasyncdeffetch_all(urls:list[str])->list[str]:asyncwithaiohttp.ClientSession()assession:# 一个session复用所有请求tasks=[fetch_one(session,url)forurlinurls]returnawaitasyncio.gather(*tasks)asyncdeffetch_one(session:aiohttp.ClientSession,url:str)->str:asyncwithsession.get(url)asresp:returnawaitresp.text()
反模式3:无限制的并发
# ❌ 错误:一次性创建10000个协程asyncdeffetch_10000_urls(urls:list[str]):asyncwithaiohttp.ClientSession()assession:tasks=[fetch_one(session,url)forurlinurls]returnawaitasyncio.gather(*tasks)# 10000个并发请求!# 问题:# 1. 内存爆炸(每个协程占用内存)# 2. 文件描述符耗尽# 3. 目标服务器被压垮# 4. 操作系统连接数限制# ✅ 正确:使用信号量控制并发数asyncdeffetch_with_limit(urls:list[str],max_concurrent:int=50):semaphore=asyncio.Semaphore(max_concurrent)asyncwithaiohttp.ClientSession()assession:asyncdeflimited_fetch(url):asyncwithsemaphore:returnawaitfetch_one(session,url)tasks=[limited_fetch(url)forurlinurls]returnawaitasyncio.gather(*tasks)

二、结构化并发:TaskGroup vs asyncio.gather

2.1 asyncio.gather 的问题

asyncio.gather是最常用的并发工具,但它有一些隐含问题:

# gather的问题:一个任务异常,其他任务的行为不确定asyncdefmain():asyncdefok():awaitasyncio.sleep(1)return"ok"asyncdeffail():awaitasyncio.sleep(0.5)raiseValueError("boom")# 默认行为:一个失败,其他被取消results=awaitasyncio.gather(ok(),fail())# 但cancel不是立即的,可能有竞态条件# 更严重的问题:任务泄漏asyncdefleaky():task=asyncio.create_task(some_long_running_coro())# 如果这里抛异常,task永远不会被等待或取消# 它会在后台默默运行,消耗资源

2.2 TaskGroup:Python 3.11+ 的结构化并发

importasyncio# ✅ TaskGroup:更安全的并发管理asyncdefstructured_concurrent():asyncwithasyncio.TaskGroup()astg:task1=tg.create_task(fetch_data("url1"))task2
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/10 9:15:47

DataGrip新手必看:从连接数据库到创建Schema的保姆级图文指南

DataGrip新手入门:从零开始掌握数据库管理的核心操作 第一次打开DataGrip时,许多从Navicat等传统数据库工具转来的开发者都会感到一丝不适应——这个由JetBrains打造的数据库IDE有着完全不同的界面逻辑和操作哲学。但别担心,这正是它强大之处…

作者头像 李华
网站建设 2026/5/10 9:14:53

构建AI智能体技能库:模块化设计、核心实现与工程实践

1. 项目概述:一个面向AI智能体的技能库最近在折腾AI智能体(Agent)的开发,发现一个挺有意思的现象:很多开发者,包括我自己在内,在构建一个能自主执行任务的智能体时,常常会陷入“重复…

作者头像 李华
网站建设 2026/5/10 9:13:39

5款免费VeLoCity皮肤:终极美化方案让VLC播放器焕然一新

5款免费VeLoCity皮肤:终极美化方案让VLC播放器焕然一新 【免费下载链接】VeLoCity-Skin-for-VLC Castom skin for VLC Player 项目地址: https://gitcode.com/gh_mirrors/ve/VeLoCity-Skin-for-VLC 还在忍受VLC播放器那个单调乏味的默认界面吗?Ve…

作者头像 李华
网站建设 2026/5/10 9:11:32

技术决策的政治学:选型背后的权力与利益分配

技术选型不是单纯的技术问题对于软件测试从业者而言,技术选型是工作中绕不开的关键环节。小到一款测试工具的选用,大到整个测试框架的搭建,每一次决策都深刻影响着后续测试工作的效率、质量与成本。然而,很多从业者往往将技术选型…

作者头像 李华