loop = asyncio.get_running_loop()
html = await loop.run_in_executor(None, requests.get, url)
async with httpx.AsyncClient() as c:
r = await c.get(url, timeout=8)
协程里用 requests 抓一个慢接口,单个请求要八秒,这八秒内所有定时任务和心跳全部停住,日志里心跳间隔从五秒直接跳到十三秒。这类现象通常不是突然出现的,往前翻半天日志能看到苗头。
追下去是这么回事:requests 是同步阻塞库,调用期间一直占着执行协程的那个线程,事件循环没法切到别的任务,只能原地等它返回,整条循环就被一个网络请求按住。
围绕「asyncio 阻塞调用」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。权限不要一口气开到最大,先加到够用再往上试,范围小才好收。
处理上按这个顺序:把阻塞调用挪进 run_in_executor 交给专用线程池执行,别直接放在协程里;把 requests 换成 aiohttp 或者 httpx 的异步客户端,请求接口层统一改一遍;只改热点接口,剩下的同步代码先留在 executor 里跑,别一次全换。
确认没问题再收工,同一个八秒请求期间心跳日志仍是五秒一条,中间没有出现空档,任务也没有积压。
