使用asyncio和aiohttp调用YouTube API时在第101个任务处冻结
调试YouTube API批量请求冻结问题的方案
你当前的代码一次性创建了800个异步任务(40000/50),直接用asyncio.gather全部提交,很容易因为并发过载、API限流或单个请求卡住导致整体冻结。以下是具体调试和修复步骤:
1. 限制并发请求数
一次性发起数百个请求会耗尽本地连接池,也会触发YouTube API的限流机制。用asyncio.Semaphore控制并发数,比如限制同时最多10个请求:
import asyncio import time import aiohttp from aiohttp.client import ClientSession results = [] chunks = [你的ID分块列表] async def fetch_chunk(session, semaphore, chunk): params = {'key': 'yourapikey', 'part': 'statistics,contentDetails,snippet', 'id': chunk } url = "https://www.googleapis.com/youtube/v3/videos" async with semaphore: try: async with session.get(url=url, params=params, ssl=False, timeout=aiohttp.ClientTimeout(total=15)) as response: return await response.json() except Exception as e: print(f"请求chunk失败: {str(e)}") return None async def get_data(): semaphore = asyncio.Semaphore(10) # 限制并发数,可根据情况调整 connector = aiohttp.TCPConnector(limit=20) # 配置连接池大小 async with aiohttp.ClientSession(connector=connector) as session: tasks = [fetch_chunk(session, semaphore, chunk) for chunk in chunks] print(f"总任务数: {len(tasks)}") raw_results = await asyncio.gather(*tasks, return_exceptions=True) # 过滤无效结果和异常 global results results = [res for res in raw_results if res is not None and not isinstance(res, Exception)] print(f"有效结果数: {len(results)}") asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) start = time.time() asyncio.run(get_data()) print(f"总耗时: {time.time() - start}")
2. 添加超时与异常捕获
单个请求卡住(比如网络波动、API无响应)会导致整个gather挂起。给每个请求加超时限制,同时用return_exceptions=True让gather不会因单个任务失败而终止,还能捕获并打印异常信息定位问题。
3. 定位问题chunk
- 先测试前150个任务,确认是否稳定卡在第101个;
- 单独提取第101个chunk的ID,用curl或Postman手动调用API,检查是否存在无效ID、API返回错误(比如403权限不足、429请求超限)。
4. 检查YouTube API配额与限流
- 登录Google Cloud控制台查看API配额剩余量,确认是否已经耗尽;
- 在请求中打印响应状态码,若频繁出现
429 Too Many Requests,需降低并发数或增加请求间隔。
内容的提问来源于stack exchange,提问作者Maciej_Solowiej
相关产品推荐
相关产品推荐

