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

为何5个API并行调用迭代耗时超预期?代码排查求助

问题排查与解决方案

核心原因分析

你的代码并发逻辑本身是正确的,但实际运行表现出串行耗时,大概率是以下原因之一:

  • 目标API的并发限制:多数API服务器会对同一来源IP的并发请求数做限制,强制将请求串行处理,导致5个请求的耗时累加为单请求的5倍左右。
  • requests未复用TCP连接:每个requests.get都会新建TCP连接,握手+传输的时间被重复计算,而单测时的0.2秒包含了连接建立时间,多请求时连接开销叠加。
  • 线程池执行的隐性等待:虽然executor.map会启动并行任务,但如果API响应存在严重的时序依赖(比如服务器端对请求做排队处理),也会表现出串行耗时。

验证方法

在call_api函数中添加时间戳打印,确认请求的执行时序:

def call_api(url):
    start = time.time()
    print(f"Start {url} at {start:.4f}")
    try:
        response = requests.get(url)
        end = time.time()
        print(f"End {url} at {end:.4f}, took {end-start:.4f}s")
        return response.status_code == 200
    except requests.exceptions.RequestException as e:
        end = time.time()
        print(f"Fail {url} at {end:.4f}, took {end-start:.4f}s")
        return False

如果输出的5个请求Start时间几乎一致,说明线程池确实在并行执行,问题出在API服务器端;如果Start时间依次延迟约0.2秒,说明请求被强制串行处理。

解决方案

1. 复用TCP连接(减少连接开销)

使用requests.Session复用连接,避免每次请求都新建TCP连接,大幅降低握手时间开销:

# 在全局创建Session对象
session = requests.Session()

def call_api(url):
    try:
        response = session.get(url)  # 使用session发起请求
        return response.status_code == 200
    except requests.exceptions.RequestException:
        return False

2. 调整线程池配置(备选方案)

如果API服务器对线程识别有特殊限制,可以尝试:

  • 适度增大max_workers到10(但不要过大,避免触发更严格的限流)
  • 改用ProcessPoolExecutor(适合CPU密集场景,IO密集场景下线程池更高效,此为备选):
with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
    results = executor.map(call_api, random_urls)

3. 排查API限流规则

查看目标API的官方文档,确认是否有并发请求数、QPS限制:

  • 如果有限流,需调整请求策略(比如增加请求间隔、使用合规代理IP分散请求来源)
  • 联系API服务商调整权限(若有需求)

4. 代码细节优化(提升效率)

避免使用global变量跟踪统计信息,改用列表批量收集结果后生成DataFrame,提升运行效率:

# 示例:用列表收集结果,替代全局DataFrame的逐行修改
results_list = []
min_time = float('inf')
max_time = float('-inf')
total_time = 0

def process_iteration(iteration):
    global min_time, max_time, total_time
    random_urls = df['url_column'].sample(n=5).tolist() 
    start_time = time.time()
    
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        results = list(executor.map(call_api, random_urls))
    
    iteration_time = time.time() - start_time
    min_time = min(min_time, iteration_time)
    max_time = max(max_time, iteration_time)
    total_time += iteration_time
    passed = 'Y' if all(results) else 'N'
    return [iteration, passed, iteration_time]

# 批量收集结果
for i in range(1, num_iterations + 1):
    results_list.append(process_iteration(i))

# 生成DataFrame
results_df = pd.DataFrame(results_list, columns=['Iteration', 'Pass', 'Time Taken'])

验证效果

修改后重新运行测试:

  • 若为连接复用问题,迭代耗时会明显接近单请求耗时
  • 若为API限流问题,耗时可能仍接近串行总和,此时需针对性调整请求策略

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:17:48