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

如何在FastAPI中使用线程池并行执行GitLab项目查询请求(无需修改现有GitLab调用方法)

如何在FastAPI中使用线程池并行执行GitLab项目查询请求(无需修改现有GitLab调用方法)

我太懂你这种串行请求慢到让人抓狂的感受了——每个请求2秒,几十个ID下来就得等好几分钟,完全没法忍!好在咱们不用修改gitlab.py里的现有方法,利用Python的asyncio就能轻松实现并行请求,效果和你想要的“10线程池”一样高效,甚至更适配异步环境。

问题根源

你之前的代码(包括gitlab.py里的projects函数)都是串行执行的:每调用一次await gitlab.project(id),都得等这个请求完全返回后才会处理下一个ID,自然累积耗时就爆炸了。

解决方案:用asyncio.gather+信号量实现并行

因为gitlab.project(id)本身是异步函数,而且已经用了全局的httpx.AsyncClient(它天生支持并发请求),我们直接用asyncio.gather来同时调度多个异步任务就行。再加个Semaphore控制并发数(比如你想要的10个),避免一下子发太多请求触发GitLab的API限流。

具体代码修改

在你的FastAPI路由里,把原来的串行逻辑改成下面这样:

import asyncio
from typing import List, Union

# 你的FastAPI路由函数
@app.get("/projects")
async def get_projects(ids: List[Union[str, int]]):
    # 定义信号量,限制同时最多10个并发请求
    semaphore = asyncio.Semaphore(10)
    
    # 包装一个带信号量的请求函数,确保并发数不超标
    async def fetch_project(id: str):
        async with semaphore:
            return await gitlab.project(id)
    
    # 创建所有异步任务,然后并行执行
    tasks = [fetch_project(str(id)) for id in ids]
    results = await asyncio.gather(*tasks)
    
    # 处理返回结果,和你原来的逻辑一致
    projects_dict = {}
    for id, p in zip(ids, results):
        if p and 'error' not in p:
            projects_dict[int(id)] = p
    
    return projects_dict

为什么这招管用?

  1. asyncio.gather:它会把所有异步任务一次性调度到事件循环中,让它们同时执行(而不是等前一个完成再开始下一个),彻底告别串行等待。
  2. Semaphore:相当于一个“并发闸门”,每次只允许10个请求同时发送,既满足你想要的“10线程级并发”,又不会因为请求太密集被GitLab限流。
  3. 无需修改gitlab.py:我们只是在外层包装了请求逻辑,完全没碰里面的project和projects方法,完美符合你的需求。

额外小贴士

  • 可以根据GitLab的API限流规则调整Semaphore的数值(GitLab默认每分钟允许1000个请求,10个并发是很安全的)。
  • 全局的httpx.AsyncClient已经帮你复用了HTTP连接,这会进一步提升并行请求的效率,不用额外做优化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 09:12:58