You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 01:01:33