惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
博客园 - 【当耐特】
月光博客
月光博客
C
Check Point Blog
T
The Blog of Author Tim Ferriss
罗磊的独立博客
博客园 - Franky
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
腾讯CDC
美团技术团队
N
Netflix TechBlog - Medium
Stack Overflow Blog
Stack Overflow Blog
Y
Y Combinator Blog
L
LangChain Blog
The Cloudflare Blog

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
Token Bucket 算法
2016-11-05 · via Jiajun的技术笔记

最近在看celery代码,看到worker的代码,发现了tocket bucket算法,自己之前还一直 在想像有些API对调用次数有限制是怎么做到的,看完才发现,原来是这么朴素的算法。 真是无知,无知啊。嗯,以后要多读读源码。

celery外链里但是写上了注释的代码(稍微做了一些改动):

.. code:: python

# coding: utf-8 import time

class TokenBucket(object):
    def __init__(self, tokens, fill_rate):
        """tokens is the total tokens in the bucket. fill_rate is the
        rate in tokens/second that the bucket will be refilled."""
        self.capacity = tokens  # 桶的容量
        self._tokens = tokens  # 令牌们
        self.fill_rate = fill_rate  # 每秒放入的令牌数量
        self.timestamp = int(time.time())  # 上次请求令牌的时间

    def consume(self, tokens):
        """Consume tokens from the bucket. Returns True if there were
        sufficient tokens otherwise False."""
        if tokens <= self.__get_tokens():
            self._tokens -= tokens
        else:
            return False
        return True

    def __get_tokens(self):
        now = int(time.time())
        if self._tokens < self.capacity:
            delta = self.fill_rate * (now - self.timestamp)
            self._tokens = min(self.capacity, self._tokens + delta)
            print("delta: %s" % delta)
        self.timestamp = now
        return self._tokens

if __name__ == "__main__":
    bucket = TokenBucket(80, 1)
    print("tokens = %s" % bucket._tokens)
    print("consume(10) = %s" % bucket.consume(10))
    print("consume(10) = %s" % bucket.consume(10))
    time.sleep(1)
    print("tokens = %s" % bucket._tokens)
    time.sleep(1)
    print("tokens = %s" % bucket._tokens)
    print("consume(90) = %s" % bucket.consume(90))
    print("tokens = %s" % bucket._tokens)
    print("consume(90) = %s" % bucket.consume(90))
    print("tokens = %s" % bucket._tokens)

我们看一下测试结果:

.. code:: bash

$ python token_bucket.py
tokens = 80
consume(10) = True
delta: 0
consume(10) = True
tokens = 60
tokens = 60
delta: 2
consume(90) = False
tokens = 62
delta: 0
consume(90) = False
tokens = 62

最后我们用大白话来描述一下上面的代码:

1,初始化的时候,指定了桶的大小和每秒钟放入令牌的速率

2,每次消耗令牌的时候,都会计算,上次消耗到本次消耗之间产生了多少令牌,如果产生 令牌的数量超过了容量,则丢弃多余的令牌。

3,如果要消耗的令牌数量大于现有的令牌数量,则返回失败。

.. [#] https://en.wikipedia.org/wiki/Token_bucket

.. [#] http://code.activestate.com/recipes/511490/