Python异步请求入门:告别阻塞,让网络请求提速十倍

发布时间:2026/6/27 5:44:47
Python异步请求入门:告别阻塞,让网络请求提速十倍 前言做接口调用、批量数据抓取时大家最常用的是requests库。但requests是同步阻塞请求发起请求后程序会原地卡死必须等待服务器返回结果才能执行下一行代码。如果要请求100个接口串行等待会耗费大量时间。而Python异步IO可以做到等待网络响应时程序不发呆自动切换去执行其他请求。在大量IO等待的场景下效率可以提升几倍甚至几十倍。本文从零入门只讲最实用的内容先搞懂协程基础再用asyncio aiohttp实现异步网络请求最后写出可直接运行的并发爬虫代码。运行环境Python 3.7及以上支持async/await关键字。一、核心基础概念1. 两个关键字async def用来定义协程函数。普通函数调用会直接执行协程函数调用只会生成一个协程对象代码不会立刻运行。await用来挂起当前协程。遇到网络等待时让出CPU事件循环自动去执行其他任务等待IO完成后再恢复运行当前代码。2. 事件循环EventLoop异步程序的调度中枢负责调度多个协程。在新版本Python中统一使用asyncio.run()来启动事件循环不用手动创建循环。3. 异步请求库aiohttprequests只支持同步异步HTTP请求首选aiohttp它完全适配asyncio协程模型内置连接池是目前行业主流方案。安装命令pipinstallaiohttp二、第一个异步请求单条GET请求同步写法requestsimportrequestsdefsync_request():resprequests.get(https://httpbin.org/get)print(resp.status_code)print(resp.text)sync_request()异步写法aiohttpimportasyncioimportaiohttp# 定义协程函数asyncdefasync_request():# 创建会话复用连接不要频繁新建asyncwithaiohttp.ClientSession()assession:# 发起GET请求asyncwithsession.get(https://httpbin.org/get)asresp:print(状态码,resp.status)# 读取响应必须加await这是IO操作textawaitresp.text()print(text[:200])# 启动事件循环运行协程if__name____main__:asyncio.run(async_request())新手必踩坑协程函数不能直接调用执行必须交给asyncio.run()读取响应text()、json()、read()都是IO操作前面必须写await优先使用async with上下文管理器自动关闭会话与连接避免连接泄漏。三、真正的并发一次性请求多个URL单条请求看不出优势批量请求才是异步的主战场。我们用asyncio.create_task()创建任务再用asyncio.gather()收集所有任务结果实现并发执行。示例代码importasyncioimportaiohttp# 待请求的地址列表url_list[https://httpbin.org/get,https://httpbin.org/ip,https://httpbin.org/headers]asyncdeffetch(session,url):单个请求任务asyncwithsession.get(url,timeoutaiohttp.ClientTimeout(total10))asresp:returnawaitresp.json()asyncdefmain():tasks[]asyncwithaiohttp.ClientSession()assession:forurlinurl_list:# 创建异步任务taskasyncio.create_task(fetch(session,url))tasks.append(task)# 等待所有任务完成收集全部返回值resultsawaitasyncio.gather(*tasks)forresinresults:print(res)if__name____main__:asyncio.run(main())运行效果3个请求几乎同时发出总耗时只等于最慢的那一次网络请求而串行请求总耗时是三次请求时间之和。四、常用进阶用法1. POST请求传递JSON数据asyncdefpost_json(session):data{username:test,password:123456}asyncwithsession.post(urlhttps://httpbin.org/post,jsondata)asresp:returnawaitresp.json()2. 限制并发数量防止请求过猛被封IP无限并发会瞬间打爆目标服务器还容易触发反爬。可以用信号量Semaphore限制同时运行的请求数量importasyncioimportaiohttp# 最大并发数semasyncio.Semaphore(5)asyncdeflimited_fetch(session,url):asyncwithsem:# 信号量自动控制并发asyncwithsession.get(url)asresp:returnawaitresp.status3. 配置请求头、超时、连接池# 连接池配置限制最大连接数connectoraiohttp.TCPConnector(limit50)# 全局超时设置timeoutaiohttp.ClientTimeout(total15)# 请求头headers{User-Agent:Mozilla/5.0}asyncdefmain():asyncwithaiohttp.ClientSession(connectorconnector,timeouttimeout,headersheaders)assession:pass五、异步 vs 同步性能对比测试串行同步代码importtimeimportrequests urlhttps://httpbin.org/getstarttime.time()for_inrange(10):requests.get(url)print(f同步串行耗时{time.time()-start:.2f}s)异步并发代码importtimeimportasyncioimportaiohttp urlhttps://httpbin.org/getasyncdeffetch(session):asyncwithsession.get(url)asresp:awaitresp.text()asyncdefmain():tasks[]asyncwithaiohttp.ClientSession()assession:for_inrange(10):tasks.append(asyncio.create_task(fetch(session)))awaitasyncio.gather(*tasks)starttime.time()asyncio.run(main())print(f异步并发耗时{time.time()-start:.2f}s)测试结论同步10次请求总耗时约58秒异步并发仅需0.51.5秒性能差距一目了然。补充异步只优化IO等待不会提升CPU密集型代码的运行速度。CPU计算任务依然要用多进程。六、新手常见问题总结RuntimeWarning: coroutine was never awaited协程没有被调度执行必须放到create_task或者await里不能只调用函数。事件循环嵌套报错在Jupyter Notebook里会出现嵌套循环问题本地脚本直接用asyncio.run()不会出错。不要反复新建ClientSession会话会维护TCP连接池全局只创建一个Session性能最高。必须捕获异常网络请求容易超时、连接失败建议在fetch函数内部增加try-except捕获异常避免整个程序崩溃。七、完整健壮版模板可直接用于爬虫importasyncioimportaiohttp# 配置MAX_CONCURRENT10TIMEOUTaiohttp.ClientTimeout(total10)URLS[fhttps://httpbin.org/get?id{i}foriinrange(20)]semasyncio.Semaphore(MAX_CONCURRENT)asyncdefrequest_one(session,url):asyncwithsem:try:asyncwithsession.get(url,timeoutTIMEOUT)asresp:ifresp.status200:returnawaitresp.json()else:returnf异常状态码{resp.status}exceptExceptionase:returnf请求失败{url}|{str(e)}asyncdefrun_all():tasks[]connectoraiohttp.TCPConnector(limitMAX_CONCURRENT)asyncwithaiohttp.ClientSession(connectorconnector)assession:forurlinURLS:taskasyncio.create_task(request_one(session,url))tasks.append(task)resultsawaitasyncio.gather(*tasks)foriteminresults:print(item)if__name____main__:asyncio.run(run_all())结尾异步请求是Python爬虫、批量接口调用的必备技能。入门阶段牢牢抓住三点用async def写协程IO操作加await使用aiohttp.ClientSession管理连接通过gather task实现并发用信号量控制请求频率。掌握本篇内容后你就可以轻松写出高并发网络程序彻底摆脱同步阻塞带来的低效问题。后续可以继续学习异步MySQL、Redis搭建完整的异步服务。标签#Python #异步IO #asyncio #aiohttp #网络请求 #爬虫入门需要我把这篇精简成适合掘金/CSDN的排版版本吗