Skip to content

【开源自荐】throttled-py - 支持多种策略及存储选项的 Python 限流库 #6429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ZhuoZhuoCrayon opened this issue Mar 30, 2025 · 0 comments
Labels

Comments

@ZhuoZhuoCrayon
Copy link

ZhuoZhuoCrayon commented Mar 30, 2025

throttled-py

GitHub: https://github.com/ZhuoZhuoCrayon/throttled-py
简介:🔧 支持多种算法(固定窗口,滑动窗口,令牌桶,漏桶 & GCRA)及存储(Redis、内存)的高性能 Python 限流库。

🚀 功能

  • 提供线程安全的存储后端:Redis(基于 Lua 实现限流算法)、内存(基于 threading.RLock,支持 Key 过期淘汰)。
  • 支持多种限流算法:固定窗口滑动窗口令牌桶漏桶 & 通用信元速率算法(Generic Cell Rate Algorithm, GCRA)
  • 提供灵活的限流策略、配额设置 API,文档详尽。
  • 支持装饰器模式。
  • 不同存储选项均有良好的性能,单次限流 API 执行耗时换算如下(详见 Benchmarks):
    • 内存:约为 2.5 ~ 4.5 次 dict[key] += 1 操作。
    • Redis:约为 1.06 ~ 1.37 次 INCRBY key increment 操作。

🔰 安装

$ pip install throttled-py==1.1.0

🔥 快速开始

1)通用 API

2)样例

from throttled import RateLimiterType, Throttled, rate_limiter, store, utils

throttle = Throttled(
    # 📈 使用令牌桶作为限流算法。
    using=RateLimiterType.TOKEN_BUCKET.value,
    # 🪣 设置配额:每秒填充 1000 个 Token(limit),桶大小为 1000(burst)。
    quota=rate_limiter.per_sec(1_000, burst=1_000),
    # 📁 使用内存作为存储
    store=store.MemoryStore(),
)


def call_api() -> bool:
    # 💧 消耗 Key=/ping 的一个 Token。
    result = throttle.limit("/ping", cost=1)
    return result.limited


if __name__ == "__main__":
    # ✅ Total: 100000, 🕒 Latency: 0.5463 ms/op, 🚀 Throughput: 55630 req/s (--)
    # ❌ Denied: 96314 requests
    benchmark: utils.Benchmark = utils.Benchmark()
    denied_num: int = sum(benchmark.concurrent(call_api, 100_000, workers=32))
    print(f"❌ Denied: {denied_num} requests")

3)作为装饰器

from throttled import Throttled, rate_limiter, exceptions

# 创建一个每分钟允许通过 1 次的限流器。
@Throttled(key="/ping", quota=rate_limiter.per_min(1))
def ping() -> str:
    return "ping"

ping()

try:
    ping()
except exceptions.LimitedError as exc:
    # raise Rate limit exceeded: remaining=0, reset_after=60
    print(exc)
    # 在异常中获取限流结果:RateLimitResult(limited=True, state=RateLimitState(limit=1, remaining=0, reset_after=60))
    print(exc.rate_limit_result)
@ruanyf ruanyf added the weekly label Mar 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants