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

如何为asyncio aiohttp的异步请求添加超时机制?

aiohttp异步请求的超时设置方案对比

问题背景

我目前用以下代码异步调用API获取数据:

import asyncio
import pandas as pd  # 补充原代码遗漏的导入
import aiohttp  # 补充原代码遗漏的导入

async def get_data(session, ticker):
    while True:
        try:
            async with session.get(url=f'api.exec.com') as response:
                if response.status == 200:
                    data = await response.json()
                    try:
                        df = pd.DataFrame(data)
                    except ValueError:
                        print("Data is not a valid float. Retrying...")
                else:
                    print("Received non-200 status code. Retrying...")
            await asyncio.sleep(1)  
        except Exception as e:
            print("Unable to get url {} due to {}. Retrying...".format(ticker, e.__class__))
            await asyncio.sleep(1)

async def main_loop(ticker_list):
    async with aiohttp.ClientSession() as session:
        ret = await asyncio.gather(*[get_data(session, tick) for tick in ticker_list])
        return ret

datas = ['x1', 'x2', 'x3', 'x4']
results = asyncio.run(main_loop(datas))  # 修正原代码调用未定义函数的问题
print(results)

之前用requests库时,可以直接通过timeout=5或timeout=(4,7)设置超时,现在想知道用aiohttp/asyncio时该怎么实现,同时我试了三种写法,想确认哪种合适:


三种超时设置方式的说明

1. 直接在session.get中传timeout=5

这种写法完全有效,aiohttp的get方法支持直接接收数值类型的timeout参数,内部会自动将其转换为aiohttp.ClientTimeout(total=5)对象,效果和requests的timeout=5完全一致,是简单总超时需求的首选写法。

修正后的完整代码:

import asyncio
import pandas as pd
import aiohttp

async def get_data(session, ticker):
    while True:
        try:
            async with session.get(url=f'api.exec.com', timeout=5) as response:
                if response.status == 200:
                    data = await response.json()
                    try:
                        df = pd.DataFrame(data)
                    except ValueError:
                        print("Data is not a valid float. Retrying...")
                else:
                    print("Received non-200 status code. Retrying...")
            await asyncio.sleep(1)  
        except Exception as e:
            print("Unable to get url {} due to {}. Retrying...".format(ticker, e.__class__))
            await asyncio.sleep(1)

async def main_loop(ticker_list):
    async with aiohttp.ClientSession() as session:
        ret = await asyncio.gather(*[get_data(session, tick) for tick in ticker_list])
        return ret

datas = ['x1', 'x2', 'x3', 'x4']
results = asyncio.run(main_loop(datas))
print(results)

2. 传入aiohttp.ClientTimeout对象

这种方式适合需要精细化控制超时规则的场景,对应requests中timeout=(connect_timeout, read_timeout)的写法,可以分别设置请求各阶段的超时阈值:

timeout = aiohttp.ClientTimeout(
    total=5,  # 整个请求的总超时时间
    connect=2,  # 建立连接的超时时间
    sock_read=3,  # 读取响应数据的超时时间
    sock_connect=2  # 套接字连接的超时时间
)

将这个对象传入session.get,就能精准控制请求不同阶段的超时逻辑,适合对超时规则有复杂要求的场景。

3. 在ClientSession全局设置超时

这种方式会给当前session下的所有请求设置默认超时,适合所有请求超时规则一致的场景,避免重复代码。如果某个请求需要特殊的超时规则,直接在该请求的get方法中单独设置timeout参数即可,请求级别的设置会覆盖全局的session设置。

修正后的代码:

import asyncio
import pandas as pd
import aiohttp

async def get_data(session, ticker):
    while True:
        try:
            async with session.get(url=f'api.exec.com') as response:
                if response.status == 200:
                    data = await response.json()
                    try:
                        df = pd.DataFrame(data)
                    except ValueError:
                        print("Data is not a valid float. Retrying...")
                else:
                    print("Received non-200 status code. Retrying...")
            await asyncio.sleep(1)  
        except Exception as e:
            print("Unable to get url {} due to {}. Retrying...".format(ticker, e.__class__))
            await asyncio.sleep(1)

async def main_loop(ticker_list):
    timeout = aiohttp.ClientTimeout(total=5)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        ret = await asyncio.gather(*[get_data(session, tick) for tick in ticker_list])
        return ret

datas = ['x1', 'x2', 'x3', 'x4']
results = asyncio.run(main_loop(datas))
print(results)

总结选择建议

  • 仅需简单总超时:用方式1(直接传数值)最简洁;
  • 需要分阶段控制超时:用方式2(传ClientTimeout对象);
  • 所有请求超时规则一致:用方式3(全局设置)减少重复代码。

内容的提问来源于stack exchange,提问作者anarchy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:15:11