0

0

asyncio.Semaphore 如何与 async 限流装饰器结合使用

舞夢輝影

舞夢輝影

发布时间:2026-01-31 12:49:02

|

397人浏览过

|

来源于php中文网

原创

asyncio.Semaphore必须全局共享,不能在装饰器内每次新建;正确做法是在模块级初始化后传入装饰器,使用async with确保协程安全,并优先选用BoundedSemaphore防止计数错乱。

asyncio.semaphore 如何与 async 限流装饰器结合使用

asyncio.Semaphore 必须全局共享,不能在装饰器里每次新建

直接在装饰器内部 asyncio.Semaphore(5) 是常见错误——每次调用被装饰函数都会创建新实例,限流完全失效。信号量必须在模块级或类属性层面初始化一次,再透传或闭包捕获。

  • ✅ 正确:在模块顶部定义 sem = asyncio.Semaphore(3),装饰器内只引用它
  • ❌ 错误:def rate_limit(n=3): return lambda f: async def wrapper(...): sem = asyncio.Semaphore(n); async with sem: ... → 每次 wrapper 都新建信号量
  • 装饰器本身不感知事件循环,所以不能在 __call__ 里创建 sem;必须提前构造好并绑定

写一个可复用的 async 限流装饰器,支持传参和协程安全

核心是让装饰器接收已创建的 semaphore 实例(而非数字),避免隐式状态。这样既灵活又可控,还能配合配置热重载。

import asyncio

def with_semaphore(sem): def decorator(func): async def wrapper(*args, *kwargs): async with sem: return await func(args, **kwargs) return wrapper return decorator

使用示例

sem = asyncio.Semaphore(2) @with_semaphore(sem) async def fetch_data(url): await asyncio.sleep(0.5) # 模拟请求 return f"done: {url}"

  • 不推荐用 @rate_limit(3) 这种“数字即限流”的写法,容易掩盖信号量生命周期问题
  • 若需动态调整上限,应替换 sem 引用(如用 asyncio.BoundedSemaphore + 外部锁保护),而非改装饰器参数
  • 装饰器返回的 wrapper 必须是 async def,否则 await func() 会报 RuntimeWarning: coroutine 'xxx' was never awaited

与 FastAPI / aiohttp 等框架集成时,注意作用域和生命周期

在 Web 框架中,semaphore 应作为全局单例或依赖注入对象存在,绝不能在每个请求路径函数里 new 一个。

Build AI
Build AI

为您的业务构建自己的AI应用程序。不需要任何技术技能。

下载
  • FastAPI 中:在 main.py 顶层定义 sem = asyncio.Semaphore(10),然后在路由函数或依赖中直接使用
  • aiohttp 中:把 sem 作为 ClientSession 的上下文属性或中间件状态传递,不要塞进 request.app['sem'] 后每次取 —— 它本来就是线程/协程安全的,无需额外封装
  • 如果用类封装业务逻辑(如 APIClient),把 sem 作为 __init__ 参数传入并存为实例属性,比用 @staticmethod + 全局变量更清晰

为什么不用 asyncio.BoundedSemaphore?它更适合装饰器场景

asyncio.BoundedSemaphore 会在 release() 超出初始值时抛出 ValueError,这对装饰器尤其重要——万一异常导致 async with 未执行完,普通 Semaphore 会悄悄“多释放”,最终计数错乱、限流失效。

  • 装饰器里若混用手动 acquire()/release()(比如加日志或超时逻辑),BoundedSemaphore 是兜底保险
  • 但只要坚持用 async with sem:,两者行为一致;差异只在“防御性编程”层面
  • 初始化仍用相同参数:asyncio.BoundedSemaphore(5),其余代码无需改动

实际项目中最容易被忽略的一点:信号量不是“请求限流器”,它只控制同时进入某段代码的协程数。如果你在装饰器里限的是「数据库查询」,但被装饰函数里又并发发了 5 个 HTTP 请求,那这 5 个请求依然不受控——限流粒度必须和你要保护的资源严格对齐。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

178

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

217

2025.12.18

Python FastAPI异步API开发_Python怎么用FastAPI构建异步API
Python FastAPI异步API开发_Python怎么用FastAPI构建异步API

Python FastAPI 异步开发利用 async/await 关键字,通过定义异步视图函数、使用异步数据库库 (如 databases)、异步 HTTP 客户端 (如 httpx),并结合后台任务队列(如 Celery)和异步依赖项,实现高效的 I/O 密集型 API,显著提升吞吐量和响应速度,尤其适用于处理数据库查询、网络请求等耗时操作,无需阻塞主线程。

27

2025.12.22

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

82

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

208

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

191

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

55

2026.01.05

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

30

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 54万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号