curl_cffi 0.5.7 AsyncSession超时及线程挂起问题求助
curl_cffi AsyncSession 持续超时/性能波动问题排查与解决
问题背景
使用curl_cffi 0.5.7版本,基于AsyncSession编写异步请求代码,初期运行正常,一段时间后出现性能下降、超时频发(ErrCode:28),甚至线程挂起。修改session.py的资源回收逻辑后,线程不再挂起,但仍会无规律出现持续数分钟的超时,重启程序可恢复,已排除代理问题。
原始代码
请求逻辑代码
async def load_url(url: str, session: AsyncSession): try: ans = await session.get(url, proxies={proxieshere}, headers={headershere}, impersonate="chrome110", timeout=5) # ... 后续处理逻辑 except Exception as exc: print("Exception: {}".format(str(exc))) async def setup(): while 1: async with AsyncSession(max_clients=5) as session: tasks = [] for url in urls: task = load_url(url=url, session=session) tasks.append(task) await gather(*tasks,return_exceptions=True)
报错信息
Failed to perform, ErrCode: 28, Reason: 'Operation timed out after 5005 milliseconds with 41047 bytes received'
已尝试的修改
修改session.py中的请求处理逻辑,将原代码:
try: # curl.debug() await self.acurl.add_handle(curl) # print(curl.getinfo(CurlInfo.CAINFO)) curl.clean_after_perform() except CurlError as e: curl.reset() self.push_curl(curl) raise RequestsError(e) rsp = self._parse_response(curl, req, buffer, header_buffer) curl.reset() self.push_curl(curl) return rsp
改为:
try: # curl.debug() await self.acurl.add_handle(curl) # print(curl.getinfo(CurlInfo.CAINFO)) except CurlError as e: raise RequestsError(e) else: rsp = self._parse_response(curl, req, buffer, header_buffer) return rsp finally: curl.reset() self.push_curl(curl)
修改后线程不再挂起,但仍存在无规律的超时波动问题。
解决方案建议
1. 调整Session复用策略
原代码每次循环都创建新AsyncSession,频繁创建销毁会导致资源开销增大、curl句柄池复用效率下降。改为复用单个Session:
async def setup(): async with AsyncSession(max_clients=5) as session: while 1: tasks = [] for url in urls: task = load_url(url=url, session=session) tasks.append(task) await gather(*tasks, return_exceptions=True) # 可选:添加短暂延迟,避免过度请求触发目标限流 await asyncio.sleep(0.1)
2. 优化超时参数与重试机制
针对ErrCode:28的超时问题,分离连接超时与读取超时,并增加重试逻辑:
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10), retry=retry_if_exception_type((RequestsError, Exception))) async def load_url(url: str, session: AsyncSession): try: # 分离连接超时(2秒)和读取超时(5秒) ans = await session.get(url, proxies={proxieshere}, headers={headershere}, impersonate="chrome110", timeout=(2, 5)) # ... 后续处理逻辑 return ans except Exception as exc: print("Exception: {}".format(str(exc))) raise
3. 升级curl_cffi版本
curl_cffi 0.5.7存在异步句柄管理的已知bug,建议升级到最新稳定版本(如>=0.6.0),新版本修复了多个异步Session的资源泄漏和超时相关问题。
4. 监控系统资源使用
程序运行时监控CPU、内存、文件描述符的使用情况,确认是否存在资源耗尽导致的性能波动:
import psutil import asyncio async def monitor_resources(): while True: process = psutil.Process() print(f"内存使用: {process.memory_info().rss / 1024 / 1024:.2f} MB") print(f"文件描述符: {process.num_fds()}") await asyncio.sleep(60) # 在setup中启动监控任务 async def setup(): async with AsyncSession(max_clients=5) as session: asyncio.create_task(monitor_resources()) while 1: # ... 原有请求逻辑
总结
核心问题大概率是Session频繁创建销毁导致的curl句柄复用效率低下,以及旧版本curl_cffi的异步资源管理bug。通过复用Session、升级版本、优化超时重试逻辑,可有效解决无规律超时波动问题。
内容的提问来源于stack exchange,提问作者PythonDev
相关产品推荐
相关产品推荐

