You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何抑制Python asyncio库针对长时间正常任务抛出的TimeoutError异常

如何抑制Python asyncio库针对长时间正常任务抛出的TimeoutError异常

首先得澄清一个关键点:asyncio本身不会平白无故给长时间运行的IO密集型任务抛出TimeoutError——你遇到的这个问题,大概率是aiohttp的默认超时设置在起作用,或者你在代码里不小心用了asyncio.wait_for这类强制超时的包装。下面给你几个针对性的解决方案:


1. 调整aiohttp的超时配置,彻底放开大文件下载的时间限制

aiohttpClientSession默认有超时限制(比如总超时默认为5分钟),对于2GB以上的大文件来说完全不够用。你可以在创建会话时,自定义一个更适合大文件的超时规则:

from aiohttp import ClientTimeout, ClientSession
import aiofiles

# 配置超时:连接超时设为60秒(足够服务器响应),总超时设为None(不限制下载总时长)
custom_timeout = ClientTimeout(
    total=None,       # 取消总下载时长限制,适合超大文件
    connect=60,       # 连接服务器的超时时间,按需调整
    socket_read=300   # 单次读取数据的超时(比如5分钟),避免真的出现连接僵死
)

async def download_large_file(url, save_path):
    async with ClientSession(timeout=custom_timeout) as session:
        async with session.get(url) as resp:
            resp.raise_for_status()  # 先确保请求本身合法
            async with aiofiles.open(save_path, 'wb') as f:
                # 流式读取写入:既节省内存,也让事件循环感知到任务在持续活跃
                while chunk := await resp.content.read(1024*1024):  # 每次读取1MB数据块
                    await f.write(chunk)

这样设置后,只要下载过程中一直有数据传输,aiohttp就不会因为时间太长抛出超时错误;而socket_read的设置又能避免真的出现连接僵死的情况(比如服务器突然断连但未发出信号)。

2. 检查代码里是否用了asyncio.wait_for之类的强制超时

如果你曾经为了限制任务时长,用asyncio.wait_for包裹了下载任务,那即使aiohttp没超时,这个包装也会强制抛出TimeoutError。比如这种错误示例:

# 错误:强制5分钟超时,大文件肯定会触发超时
await asyncio.wait_for(download_large_file(url, path), timeout=300)

解决方法很简单:要么去掉wait_for直接await任务,要么把timeout参数设为一个足够大的值(比如3600秒,也就是1小时)。

3. 关于asyncio的“慢任务”警告(非TimeoutError相关)

如果你看到的是类似Executing <Task> took 20.0 seconds的警告,而不是TimeoutError,那是asyncio的慢回调检测机制。这个只是警告,不会终止任务,如果你觉得烦,可以调整阈值:

import asyncio

loop = asyncio.get_event_loop()
loop.slow_callback_duration = 300  # 把阈值从默认的0.1秒改成5分钟

不过这个和你遇到的TimeoutError不是一回事,仅供参考。


最后再强调下:asyncio的事件循环是基于IO多路复用的,只要你的任务在做IO操作(比如下载时读数据、写文件),它就会认为任务是活跃的,不会主动终止。你遇到的超时问题本质上是上层库的超时配置或者自己加的强制超时包装导致的,调整这些就能解决问题,完全不需要“抑制解释器的错误”。

备注:内容来源于stack exchange,提问作者mtrojak2

火山引擎 最新活动