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

如何在for循环中异步发起API请求?最简asyncio实现及问题求助

解决API请求并发执行并等待全部完成的问题

你原来代码的问题

你之前的写法有两个关键错误:

  1. loop.run_in_executor(executor, get_data(ticker)) 会立即同步执行get_data(ticker),而不是把任务提交给执行器异步处理。正确写法应该是传递函数对象和参数:loop.run_in_executor(executor, get_data, ticker)。
  2. loop.run_forever() 会让事件循环一直运行无法主动结束,应该用asyncio.gather等待所有任务完成后自动退出。

推荐实现方案

API请求属于IO密集型场景,优先选择asyncio + ThreadPoolExecutor(兼容同步函数),或者直接用异步HTTP库实现纯异步请求。

方案1:asyncio + ThreadPoolExecutor(兼容同步get_data函数)

如果你的get_data是同步函数(比如基于requests库),用线程池并发执行避免阻塞事件循环:

import asyncio
from concurrent.futures import ThreadPoolExecutor
import pandas as pd

# 你的同步get_data函数
def get_data(ticker):
    # 替换为实际API请求逻辑
    import time
    time.sleep(1)  # 模拟网络延迟
    return pd.DataFrame({'ticker': [ticker], 'close': [150 + int(ticker[-1])]})

async def main(tickers):
    # 线程池大小根据API并发限制调整,比如5-10
    with ThreadPoolExecutor(max_workers=5) as executor:
        loop = asyncio.get_running_loop()
        # 批量提交所有任务,收集future对象
        tasks = [loop.run_in_executor(executor, get_data, ticker) for ticker in tickers]
        # 等待所有任务完成,获取所有DataFrame结果
        results = await asyncio.gather(*tasks)
    
    # 合并结果或单独处理每个DataFrame
    combined_df = pd.concat(results, ignore_index=True)
    print(combined_df)

if __name__ == "__main__":
    tickers = ['AAPL', 'MSFT', 'GOOGL', 'TSLA']
    asyncio.run(main(tickers))

方案2:纯异步实现(推荐,需改造get_data)

如果可以用异步HTTP库(比如aiohttp)重写get_data,性能更优且无需线程池:

import asyncio
import aiohttp
import pandas as pd

async def get_data(ticker):
    # 用aiohttp发起异步API请求
    async with aiohttp.ClientSession() as session:
        # 替换为实际API地址
        api_url = f"https://api.your-finance-service.com/{ticker}"
        async with session.get(api_url) as resp:
            data = await resp.json()
            # 转换为DataFrame返回
            return pd.DataFrame(data)

async def main(tickers):
    # 创建所有异步任务
    tasks = [get_data(ticker) for ticker in tickers]
    # 等待所有任务完成,拿到结果列表
    results = await asyncio.gather(*tasks)
    
    # 合并结果示例
    combined_df = pd.concat(results, ignore_index=True)
    print(combined_df)

if __name__ == "__main__":
    tickers = ['AAPL', 'MSFT', 'GOOGL', 'TSLA']
    asyncio.run(main(tickers))

关键说明

  • asyncio.gather(*tasks):同时运行所有传入的异步任务,等待全部完成后返回结果列表,顺序与任务传入顺序一致。
  • 线程池/进程池选择:IO密集型任务用线程池足够;CPU密集型任务(如复杂计算)才考虑ProcessPoolExecutor。
  • 并发限制:不要设置过大的线程池/任务数,避免触发API限流,建议参考API文档调整max_workers。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 06:54:47