令牌桶算法的python实现,人人都可以玩算法

from redis  import Redis
import time
import math
import random

redis_conn =  Redis(host='localhost',port=6689,password="redis_user",db=0)

hasinit = False
def init_redis_key(key,times):
    redis_conn.hset(key, 'tokens', times)
    last_time = int(time.time())  # 记录令牌生成时间
    redis_conn.hset(key, 'last_time', last_time)

def can_pass_token_bucket(user, action, time_zone=60, times=30):
    """
    :param user: 用户唯一标识
    :param action: 用户访问的接口标识(即用户在客户端进行的动作)
    :param time_zone: 接口限制的时间段
    :param time_zone: 限制的时间段内允许多少请求通过
    """
    # 请求来了就倒水,倒水速率有限制
    key = '{}:{}'.format(user, action)
    global hasinit
    if not hasinit:
        init_redis_key(key,times)
        hasinit = True
    rate = times / time_zone # 令牌生成速度
    capacity = times # 桶容量
    tokens = redis_conn.hget(key, 'tokens') # 看桶中有多少令牌
    last_time = redis_conn.hget(key, 'last_time') # 上次令牌生成时间
    now = int(time.time())
    if tokens:
        tokens = int(tokens)
    else:
        tokens = capacity
    if last_time:
        last_time = int(last_time)
    else:
        last_time = now
    print("tokens:",tokens)

    delta_tokens = (now - last_time) * rate # 经过一段时间后生成的令牌
    if delta_tokens >= 1:
        tokens = tokens + math.ceil(delta_tokens) # 增加令牌
        if tokens > capacity:
            tokens = capacity
        last_time = int(time.time()) # 记录令牌生成时间
        # print("hset last_time2:",last_time)
        redis_conn.hset(key, 'last_time', last_time)

    if tokens >= 1:
        tokens = tokens - 1 # 请求进来了,令牌就减少1
        print("hset tokens2:",tokens)
        redis_conn.hset(key, 'tokens', tokens)
        return True
    return False


if __name__ == "__main__":
    i = 0
    while i < 120:
        i = i + 1
        if can_pass_token_bucket("77-88-99","get"):
            print(f"第{i}次成功")
        else:
            print(f"第{i}次失败")
        print("\n")
        # 通过sleep模拟不同时间段请求速率的不同,当请求过快,token充足,请求能通过,token不足以后,返回失败
        # 当请求速率降下来之后,token的数量能上去,可以应对突发请求  token的数值大,突发请求成功数量就多
        if  i > 1 and i < 30:
            time.sleep(0.1)
        if i > 30 and i < 60:
            t = random.randint(2,6)/10
            time.sleep(t)
        if i > 60 and i < 90:
            t = random.randint(30,41)/10
            time.sleep(t)
        if i > 90 and i < 120:
            t = random.randint(2,6)/10
            time.sleep(t)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_36013896

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值