如何使用aiohttp限制未完成的并发请求数量?
如何用aiohttp限制活跃请求数量
嘿,这个问题我太熟悉了!在aiohttp里控制同时运行的请求数量,最实用的工具就是asyncio.Semaphore——它就像一个“并发闸门”,能帮你把未完成的活跃请求数牢牢卡在设定的数值里,避免一下子发起太多请求导致服务器拒绝或者本地程序资源过载。
下面给你两种常用的解决方案,你可以根据自己的需求选:
方法一:用asyncio.Semaphore精准控制任务并发
这种方式可以单独限制图片下载任务的并发数,灵活性更高。我们只需要给你的代码加几行就行:
import asyncio import aiohttp async def get_images(url, session, semaphore): chunk_size = 100 # 先通过信号量获取“许可”,达到限制数时会自动等待 async with semaphore: print(f'Making request to {url}') async with session.get(url=url) as r: # 👉 这里要注意!原来的固定文件名会覆盖所有图片,建议改成从URL提取或用索引命名 filename = url.split('/')[-1] with open(f'path/{filename}', 'wb') as file: while True: chunk = await r.content.read(chunk_size) if not chunk: break file.write(chunk) async def main(): # 设定最多同时跑5个活跃请求,数字可以根据你的需求调整 semaphore = asyncio.Semaphore(5) # 你的待请求URL列表 image_urls = [ 'https://example.com/img1.png', 'https://example.com/img2.png', # ...更多URL ] async with aiohttp.ClientSession() as session: # 创建所有下载任务 tasks = [get_images(url, session, semaphore) for url in image_urls] # 等待所有任务完成 await asyncio.gather(*tasks) if __name__ == '__main__': asyncio.run(main())
关键说明:
asyncio.Semaphore(5):括号里的数字就是你要限制的最大活跃请求数,比如改成10就允许同时跑10个请求。async with semaphore::这个上下文管理器会自动帮你“拿许可”和“还许可”——当请求数达到上限时,新的任务会在这里等待,直到某个请求完成释放许可,才会继续执行。- 文件名的小坑:你原来的代码里固定写
name.png,所有图片都会被覆盖成同一个文件,所以我改成了从URL提取文件名,你也可以用其他方式命名(比如给每个URL加索引)。
方法二:用TCPConnector限制全局连接数
如果你想限制整个ClientSession的所有连接数(不止是图片下载请求),可以用aiohttp.TCPConnector的limit参数:
import asyncio import aiohttp async def get_images(url, session): chunk_size = 100 print(f'Making request to {url}') async with session.get(url=url) as r: filename = url.split('/')[-1] with open(f'path/{filename}', 'wb') as file: while True: chunk = await r.content.read(chunk_size) if not chunk: break file.write(chunk) async def main(): # 创建连接器,限制最多5个连接 connector = aiohttp.TCPConnector(limit=5) async with aiohttp.ClientSession(connector=connector) as session: image_urls = [ 'https://example.com/img1.png', 'https://example.com/img2.png', # ...更多URL ] tasks = [get_images(url, session) for url in image_urls] await asyncio.gather(*tasks) if __name__ == '__main__': asyncio.run(main())
两种方法的区别:
- Semaphore:只限制你指定的任务(比如这里的图片下载)的并发数,同一个session里的其他请求不受影响。
- TCPConnector:限制整个session的所有连接数,不管是什么类型的请求,最多只能有
limit个连接同时存在。
你可以根据自己的实际场景选,一般来说用Semaphore会更灵活哦!
内容的提问来源于stack exchange,提问作者CaptainDriftwood
相关产品推荐
相关产品推荐

