本文目录导读:

- 使用
time.sleep()简单限流 - 使用
time.perf_counter()精确限流 - 令牌桶算法(Token Bucket)
- 漏桶算法(Leaky Bucket)
- 使用第三方库
ratelimit - 对于循环任务的实用方案
- 推荐方案
在Python中限制高频同步任务的频次,常见的方法有以下几种,适用于不同的场景:
使用 time.sleep() 简单限流
适合对执行间隔要求不严格的场景:
import time
def rate_limited_task(interval=1.0): # 间隔1秒
while True:
# 执行你的任务
print(f"执行任务: {time.time()}")
time.sleep(interval)
使用 time.perf_counter() 精确限流
控制每秒执行次数(QPS):
import time
def rate_limiter(target_qps=5):
"""限制每秒执行次数"""
interval = 1.0 / target_qps
last_time = 0
def decorator(func):
def wrapper(*args, **kwargs):
nonlocal last_time
current_time = time.perf_counter()
elapsed = current_time - last_time
if elapsed < interval:
time.sleep(interval - elapsed)
last_time = time.perf_counter()
return func(*args, **kwargs)
return wrapper
return decorator
@rate_limiter(target_qps=5)
def my_task():
print(f"执行任务: {time.time()}")
# 使用
for _ in range(10):
my_task()
令牌桶算法(Token Bucket)
适合需要容忍突发请求的场景:
import time
import threading
class TokenBucket:
def __init__(self, rate, capacity):
"""
rate: 令牌生成速率(每秒)
capacity: 桶容量(最大突发量)
"""
self.rate = rate
self.capacity = capacity
self.tokens = capacity
self.last_refill_time = time.time()
self.lock = threading.Lock()
def consume(self, tokens=1):
"""尝试消耗令牌,返回是否成功"""
with self.lock:
self._refill()
if self.tokens >= tokens:
self.tokens -= tokens
return True
return False
def _refill(self):
"""补充令牌"""
now = time.time()
elapsed = now - self.last_refill_time
self.tokens = min(self.capacity,
self.tokens + elapsed * self.rate)
self.last_refill_time = now
def wait_and_consume(self, tokens=1):
"""阻塞直到获取到令牌"""
while not self.consume(tokens):
time.sleep(0.001) # 短暂等待
# 使用示例
bucket = TokenBucket(rate=5, capacity=10) # 每秒5个,最大突发10个
def rate_limited_task():
bucket.wait_and_consume()
print(f"执行任务: {time.time()}")
for _ in range(20):
rate_limited_task()
漏桶算法(Leaky Bucket)
适合需要平滑输出速率的场景:
import time
from collections import deque
class LeakyBucket:
def __init__(self, rate, capacity):
"""
rate: 处理速率(每秒)
capacity: 队列容量
"""
self.rate = rate
self.capacity = capacity
self.queue = deque()
self.last_process_time = time.time()
def put(self, item):
"""尝试放入队列,返回是否成功"""
if len(self.queue) < self.capacity:
self.queue.append((item, time.time()))
return True
return False
def get(self):
"""获取并处理任务"""
if not self.queue:
return None
# 检查是否可以处理
now = time.time()
elapsed = now - self.last_process_time
if elapsed >= 1.0 / self.rate:
self.last_process_time = now
return self.queue.popleft()[0]
return None
# 使用示例
bucket = LeakyBucket(rate=2, capacity=5) # 每秒处理2个,队列容量5
def process_task():
task = bucket.get()
if task:
print(f"处理任务 {task} at {time.time()}")
# 模拟任务提交
for i in range(10):
bucket.put(f"task_{i}")
# 处理任务
for _ in range(10):
process_task()
time.sleep(0.3) # 模拟处理间隔
使用第三方库 ratelimit
需要先安装:pip install ratelimit
from ratelimit import limits, sleep_and_retry
import time
@sleep_and_retry
@limits(calls=5, period=1) # 每秒最多5次调用
def my_task():
print(f"执行任务: {time.time()}")
# 使用
for _ in range(15):
my_task()
对于循环任务的实用方案
混合使用时间检查和睡眠:
import time
class SimpleRateLimiter:
def __init__(self, max_calls, period=1.0):
"""
max_calls: 周期内最大调用次数
period: 时间周期(秒)
"""
self.max_calls = max_calls
self.period = period
self.call_times = []
def acquire(self):
"""阻塞直到可以执行"""
now = time.time()
# 移除过期的记录
self.call_times = [t for t in self.call_times
if now - t < self.period]
if len(self.call_times) >= self.max_calls:
# 计算需要等待的时间
wait_time = self.call_times[0] + self.period - now
if wait_time > 0:
time.sleep(wait_time)
self.call_times.append(time.time())
# 使用示例
limiter = SimpleRateLimiter(max_calls=10, period=1)
for _ in range(30):
limiter.acquire()
print(f"执行任务: {time.time()}")
推荐方案
- 简单场景:使用
time.sleep() - 需要精确控制QPS:使用令牌桶算法
- 需要平滑输出:使用漏桶算法
- 快速实现:使用
ratelimit库 - 生产环境:推荐使用
TokenBucket或LeakyBucket
选择哪种方案取决于你的具体需求:是否需要容忍突发、是否需要精确控制、是否允许等待等。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播