Python使用asyncio把接口耗时从30秒压到3秒的示例代码

 更新时间:2026年11月10日 08:49:49   作者:风骏时光牛马  
还在为接口耗时30秒头疼,本文手把手教你用Python asyncio把批量接口调用从30秒压到3秒,通过协程、事件循环和并发原语,轻松实现高并发I/O优化,避开同步库混用、无上限并发等坑,快来看看如何让你的代码飞起来,需要的朋友可以参考下

一、问题场景

假设要批量拉取 30 个外部接口的数据做聚合,同步写法如下:

import requests, time

def fetch(url):
    return requests.get(url, timeout=5).json()

start = time.time()
data = [fetch(u) for u in URLS]   # 30 个串行请求
print(time.time() - start)        # 约 30s

这类任务的瓶颈在 I/O 等待,CPU 基本空转。线程池能缓解,但线程切换与内存开销随并发数线性增长;asyncio 用单线程协程在等待期间切换任务,更适合高并发 I/O 场景。

二、核心机制

  • 协程(coroutine):async def 定义,调用后返回协程对象,不会立即执行。
  • 事件循环(event loop):调度所有就绪任务,是异步运行的中枢。
  • await:把控制权交还事件循环,遇到 I/O 时才真正让出,因此必须使用异步版库。
  • 并发原语:asyncio.gather 批量并发;Semaphore 限流;asyncio.timeout 控制总耗时。

一个关键原则:不要在协程里写阻塞调用。requests、time.sleep、同步数据库驱动都会阻塞整个事件循环,把并发全部拖死。

三、代码演示

import asyncio, aiohttp, time

URLS = [f"[https://httpbin.org/delay/1?n={i}](https://httpbin.org/delay/1?n={i})" for i in range(30)]
CONCURRENCY = 10          # 单域名并发上限,避免压垮对端

async def fetch(session, url, sem):
    async with sem:                       # 限流
        async with session.get(url, timeout=5) as resp:
            return await resp.json()

async def main():
    sem = asyncio.Semaphore(CONCURRENCY)
    timeout = aiohttp.ClientTimeout(total=5)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        tasks = [fetch(session, u, sem) for u in URLS]
        results = await asyncio.gather(*tasks, return_exceptions=True)
    ok = [r for r in results if not isinstance(r, Exception)]
    print(f"成功 {len(ok)} / {len(URLS)}")
    return ok

if __name__ == "__main__":
    start = time.time()
    asyncio.run(main())
    print(f"总耗时 {time.time() - start:.2f}s")   # 约 3.2s

耗时从 30s 降到 3s 左右,本质是把「串行等待」改成了「并行等待」。

再加一层超时兜底与重试,生产环境更稳:

async def fetch_with_retry(session, url, sem, retry=2):
    for attempt in range(retry + 1):
        try:
            async with sem:
                async with asyncio.timeout(5):
                    async with session.get(url) as resp:
                        resp.raise_for_status()
                        return await resp.json()
        except (asyncio.TimeoutError, aiohttp.ClientError):
            if attempt == retry:
                raise
            await asyncio.sleep(2 ** attempt)   # 指数退避

四、避坑清单

  1. 同步库混用:非要用 requests 时,用 asyncio.to_thread() 包一层,别直接调用。
  2. 无上限并发:gather 一次性展开三千个任务会打爆连接池,必须加 Semaphore。
  3. 异常吞没:gather 默认遇到异常即抛出,其余任务被取消;需要全部结果时加 return_exceptions=True。
  4. CPU 密集任务:异步无收益,应交给 ProcessPoolExecutor。
  5. 资源未释放:ClientSession 必须用 async with 管理,否则连接泄漏。

五、小结

asyncio 的收益来自 I/O 等待占比。判断标准很直接:任务耗时是否主要花在等网络、等磁盘、等数据库。如果是,异步能把等待时间重叠起来;如果主要花在计算,异步只会增加复杂度。落地时先量化单次请求耗时与并发上限,再决定协程数量,比盲目堆并发更可靠。

到此这篇关于Python使用asyncio把接口耗时从30秒压到3秒的示例代码的文章就介绍到这了,更多相关Python asyncio接口耗时从30秒压到3秒内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python合并多个excel的详细过程

    python合并多个excel的详细过程

    合并需求很多,常见的有相同数据结构,按行进行纵向拼接,下面这篇文章主要给大家介绍了关于python合并多个excel的相关资料,需要的朋友可以参考下
    2022-10-10
  • 在Pandas中更改DataFrame中的值

    在Pandas中更改DataFrame中的值

    这篇文章主要介绍了在Pandas中更改DataFrame中的值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Python中使用gflags实例及原理解析

    Python中使用gflags实例及原理解析

    这篇文章主要介绍了Python中使用gflags实例及原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Python中如何向函数传递列表

    Python中如何向函数传递列表

    本文主要介绍了Python中如何向函数传递列表,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • python redis 删除key脚本的实例

    python redis 删除key脚本的实例

    今天小编就为大家分享一篇python redis 删除key脚本的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-02-02
  • Flask中特殊装饰器的使用

    Flask中特殊装饰器的使用

    本文主要介绍了Flask中特殊装饰器的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • pandas读取HTML和JSON数据的实现示例

    pandas读取HTML和JSON数据的实现示例

    Pandas可以直接读取html和JSON数据,本文就来介绍一下pandas读取HTML和JSON数据的实现示例,文中通过示例代码介绍的非常详细,感兴趣的可以了解一下
    2024-01-01
  • 详解Python中@staticmethod和@classmethod区别及使用示例代码

    详解Python中@staticmethod和@classmethod区别及使用示例代码

    这篇文章主要介绍了详解Python中@staticmethod和@classmethod区别及使用示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • PyCharm运行bash脚本的实现

    PyCharm运行bash脚本的实现

    本文主要介绍了PyCharm运行bash脚本的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域

    matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域

    这篇文章主要介绍了matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01

最新评论