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

如何在Python中高效处理6000个API请求以缩短总耗时?

优化批量API请求的并行处理以缩短整体耗时

我有一个Python脚本,可向API发送请求并根据输入提示生成响应,每个请求通常耗时约10秒。现有一份6000行数据的CSV文件,需要将其中text列的值作为输入提示发送至API,并将生成的响应追加至CSV的新列中。

由于请求数量庞大,串行处理需要6000*10秒,耗时过长。以下是我当前的基础代码片段:

import pandas as pd
from requests_futures.sessions import FuturesSession
import time

# Define your existing function for sending a request
def send_request(session, input_prompt):
    url = 'https://ai-chat-test.***.workers.dev/'
    consolidated_request = f"""From the input "{input_prompt}", extract key descriptions, deduplicate them, and use these to create a compelling, concise description of the fashion item."""
    return session.post(url, json={"messages": [{"role": "user", "content": consolidated_request}]}, headers={"Content-Type": "application/json"})

# Function to apply send_request concurrently and save intermittently
def apply_concurrent_requests(df, function):
    session = FuturesSession(max_workers=5)
    futures = {function(session, text): index for index, text in enumerate(df['text'])}
    results = [None] * len(df)
    batch_counter = 0
    start_time = time.time()

    for future in as_completed(futures):
        index = futures[future]
        try:
            response = future.result()
            if response.status_code == 200:
                data = response.json()
                for message in data:
                    if message['role'] == 'assistant':
                        results[index] = message['content']
                        break
                else:
                    results[index] = "No assistant message found."
            else:
                results[index] = f"Failed to get a response, status code: {response.status_code}"
        except Exception as e:
            results[index] = f"Exception occurred: {e}"

        # Save after processing each batch of 100 or the last response
        batch_counter += 1
        if batch_counter % 100 == 0 or index + 1 == len(df):
            # Save the responses so far to the DataFrame
            for j, res in enumerate(results[:index+1]):
                df.at[j, 'response'] = res

            # Save to CSV
            df.to_csv('intermediate_metadata.csv', index=False)
            print(f"Processed {index+1} requests in {time.time() - start_time:.2f} seconds and saved to CSV.")
            start_time = time.time()  # Reset the timer for the next batch

    return df

df = pd.read_csv('metadata.csv')
updated_df = apply_concurrent_requests(df, send_request)
updated_df.to_csv('updated_metadata.csv', index=False)

优化方案

1. 合理调整并发线程数

原代码max_workers=5的并发数偏低,可根据API的限流规则(比如每秒请求数限制)适当调高至20-50区间。但需注意:

  • 过高的并发可能触发API限流(返回429状态码),建议先小批量测试,找到最优并发数。
  • 搭配重试机制,处理限流或临时网络故障。

2. 优化中间结果保存逻辑

原代码每次保存时循环遍历results[:index+1]更新DataFrame,效率极低。直接通过索引更新对应行即可:

# 替换原保存逻辑中的循环
df.at[index, 'response'] = results[index]

每次处理完一条请求就更新DataFrame对应行,批量保存时直接写入CSV即可。

3. 添加请求重试机制

使用requests.adapters.HTTPAdapter添加重试策略,处理临时失败的请求:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_session(max_workers, retries=3):
    session = FuturesSession(max_workers=max_workers)
    retry_strategy = Retry(
        total=retries,
        backoff_factor=1,  # 重试间隔依次为1s、2s、4s...
        status_forcelist=[429, 500, 502, 503, 504]
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    return session

4. 改用异步IO框架(aiohttp)

线程池的并发效率不如异步IO,对于大规模IO密集型任务,推荐使用aiohttp+asyncio实现更高并发:

异步版本示例代码

import pandas as pd
import aiohttp
import asyncio
import time
from tqdm import tqdm

async def send_request(session, input_prompt):
    url = 'https://ai-chat-test.***.workers.dev/'
    consolidated_request = f"""From the input "{input_prompt}", extract key descriptions, deduplicate them, and use these to create a compelling, concise description of the fashion item."""
    async with session.post(
        url,
        json={"messages": [{"role": "user", "content": consolidated_request}]},
        headers={"Content-Type": "application/json"}
    ) as response:
        if response.status == 200:
            data = await response.json()
            for message in data:
                if message['role'] == 'assistant':
                    return message['content']
            return "No assistant message found."
        else:
            return f"Failed to get a response, status code: {response.status}"

async def process_batch(session, batch):
    tasks = [send_request(session, text) for idx, text in batch]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return [(idx, res) for (idx, _), res in zip(batch, results)]

async def apply_async_requests(df, max_concurrent=30, batch_size=100):
    df['response'] = None
    total_rows = len(df)
    start_time = time.time()

    async with aiohttp.ClientSession() as session:
        for i in tqdm(range(0, total_rows, batch_size)):
            batch = list(df.iloc[i:i+batch_size].iterrows())
            batch_results = await process_batch(session, batch)
            for idx, res in batch_results:
                if isinstance(res, Exception):
                    df.at[idx, 'response'] = f"Exception occurred: {res}"
                else:
                    df.at[idx, 'response'] = res
            
            # 保存中间结果
            df.to_csv('intermediate_metadata.csv', index=False)
            elapsed = time.time() - start_time
            print(f"Processed {min(i+batch_size, total_rows)}/{total_rows} requests in {elapsed:.2f} seconds")
    
    return df

if __name__ == "__main__":
    df = pd.read_csv('metadata.csv')
    updated_df = asyncio.run(apply_async_requests(df))
    updated_df.to_csv('updated_metadata.csv', index=False)

5. 进度可视化

使用tqdm库添加进度条,直观显示处理进度(如上面异步代码所示)。


关键注意事项

  • API限流:务必遵守API的使用规则,避免因过高并发导致账号被封禁或请求被拒绝。
  • 中间结果保存:定期保存中间结果,防止程序崩溃导致数据丢失。
  • 异常处理:完善的异常处理能避免单个请求失败导致整个流程中断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:24:54