Python并发请求限制QPS的三种实现方案

Ruby
Ruby
发布时间:2026-10-14 | 2人浏览过
原创

本文介绍在Python中使用GRequests进行高并发API请求时,如何通过三种方式限制每秒查询率(QPS)。内容涵盖基础的time.sleep阻塞法、精确的令牌桶算法实现,以及封装好的GRequests-Throttle库。针对低并发和高并发场景提供了具体的代码示例与性能对比,帮助开发者避免服务器拒绝响应并优化资源利用率。

背景与问题描述

此前遇到一个需求,需访问某API服务器获取数据。该服务器对QPS(每秒查询率)限制为2。由于限制较低,最初采用阻塞式请求即可满足。后续服务升级,QPS上限提升至20,原有的阻塞方式已无法充分利用带宽。因此改用GRequests进行并发请求,但发现并发速度过快导致服务器频繁返回错误码,造成大量资源浪费。为此,本文记录几种有效的节流(Throttle)方案:

基础限流方案:time.sleep阻塞法

以下示例均基于相同的前提条件,包含必要的包导入及数据初始化:


import grequests

urls = [
 "https://www.baidu.com",
 "https://www.google.com"
]
requests = [
 grequests.get(url)
 for url in urls
] * 1000

rate = 20 # 表示 20 请求/秒

time.sleep(1)

这是最直观的方法,通过time.sleep(1)强制阻塞进程,从而控制每秒发出的请求数量。其耗时逻辑可表示为:Time = 请求准备时延 + 请求发送时延 + time.sleep(1)。然而,该方法存在精度不足的问题:随着数据量增大,实际QPS的方差也会随之增大,导致限流效果不够稳定。


from time import sleep

req_groups = [
 requests[i: i+rate]
 for i in range(0, len(requests), rate)
]

ret = []
for req_group in req_groups:
 ret += grequests.map(req_group)
 sleep(1)

print(ret)

精确限流方案:令牌桶算法

令牌桶(token bucket)方法

该方法精度更高,在服务器和客户端能承受高并发的前提下,可将误差控制在±1以内。其耗时公式为:Time = 请求准备时延 + 请求发送时延 + 令牌桶阻塞时延。其中,令牌桶阻塞时延 ≈ 1 - (请求准备时延 + 请求发送时延)。尽管精度提升,但该方法会导致CPU占用率看似较高(主要源于while pass循环),尽管实际有效计算负载很低。


from time import time

class Throttle:
 def __init__(self, rate):
  self.rate = rate
  self.tokens = 0
  self.last = 0
 
 def consume(self, amount=1):
  now = time()
  
  if self.last == 0:
   self.last = now
  
  elapsed = now - self.last

  if int(elapsed * self.rate):
   self.tokens += int(elapsed * self.rate)
   self.last = now
  
  self.tokens = (
   self.rate
   if self.tokens > self.rate
   else self.tokens
  )
  
  if self.tokens >= amount:
   self.tokens -= amount
  else:
   amount = 0
  
  return amount

throttle = Throttle(rate)

req_groups = [
 requests[i: i+rate]
 for i in range(0, len(requests), rate)
]

ret = []
for req_group in req_groups:
 ret += grequests.map(req_group)
 while throttle.consume():
  pass # 阻塞

print(ret)

封装库方案:GRequests-Throttle

GRequests-Throttle

这是一个基于令牌桶算法封装的GRequests修改版,使用方式极为简便。首先需安装grequests-throttle库(注:清华镜像源更新可能较慢,建议使用阿里镜像源):


pip install grequests-throttle

import grequests_throttle as gt

ret = gt.map(requests, rate=rate)
print(ret)

方案总结与建议

总结

若并发请求量较小,可直接使用time.sleep(1),实现简单快捷;若并发量较大,令牌桶算法能更充分地利用每一秒的带宽;若希望减少代码编写量,推荐使用GRequests-Throttle库进行流量控制。

关于Python并发请求下限制QPS的实现介绍至此。如需了解更多相关技术细节,可查阅本站往期文章或继续浏览后续内容。感谢支持!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表