- 时间点一:[1, 2, 3], 4, 5, 6, 7, 8, 9
- 时间点二:1, [2, 3, 4], 5, 6, 7, 8, 9
- 时间点三:1, 2, [3, 4, 5], 6, 7, 8, 9
- 时间点四:1, 2, 3, [4, 5, 6], 7, 8, 9
import json
import time
from redis import StrictRedis
redis_cli = StrictRedis()
class Demo:
"""按照资源类型限制,每种资源类型限制并发"""
LIMIT = 10
INTERVAL = 30
def __init__(self):
self.redis = redis_cli
...
def need_to_que(self, res_type: str):
"""
判断资源是否已经超过设置阈值
redis有序集合里面按照先后顺序存放资源放入的时间,大小为LIMIT的值
"""
key = f"Limit:{res_type}"
send_times = self.redis.zrange(key, 0, int(time.time() * 1000))
while send_times:
if int(send_times[0]) >= time.time() * 1000 - self.INTERVAL * 1000:
break
self.redis.zrem(key, send_times[0])
send_times.pop(0)
return send_times and len(send_times) >= self.LIMIT
def set_flag(self, res_type):
"""
任何被资源处理的时间戳放入池中
"""
key = f"Limit:{res_type}"
now = int(time.time() * 1000)
self.redis.zadd(key, {now: now})
def send_to_que(self, res_type: str, **data):
"""
被限制的资源放入队列中,由消费者二次消费
"""
key = f"Queue:{res_type}"
self.redis.rpush(key, json.dumps(data))
def action(self, res_type, data):
"""
分步操作,所以需要加锁
"""
key = f"Lock:{res_type}"
with self.redis.lock(key, 3):
if self.need_to_que(res_type):
self.send_to_que(res_type, data=data)
return "Restricted"
self.set_flag(res_type)
return "Success"
if __name__ == '__main__':
resource_type = "demo"
redis_cli.delete(f"Limit:{resource_type}", f"Queue:{resource_type}")
demo = Demo()
demo.INTERVAL = 1
demo.LIMIT = 5
print(f"规则:{demo.INTERVAL}秒并发{demo.LIMIT}次")
for i in range(20):
demo.action(resource_type, f"Action {i}")
time.sleep(0.1)
pool = redis_cli.zrange(f"Limit:{resource_type}", 0, 100)
queue = redis_cli.lrange(f"Queue:{resource_type}", 0, 100)
print(f"当前池大小:{len(pool)},任务时间戳为:{pool}")
print(f"当前被限制操作:{queue}")
print("------------------------------------------")
time.sleep(5)
for i in range(20, 40):
demo.action(resource_type, f"Action {i}")
time.sleep(1)
pool = redis_cli.zrange(f"Limit:{resource_type}", 0, 100)
queue = redis_cli.lrange(f"Queue:{resource_type}", 0, 100)
print(f"当前池大小:{len(pool)},任务时间戳为:{pool}")
print(f"当前被限制操作:{queue}")
print("------------------------------------------")