客户端发送http请求进行流量控制

客户端发送http请求进行流量控制

实现方式 1:使用 Semaphore (信号量) 控制流量

asyncio.Semaphore 是一种简单的流控方法,可以用来限制并发请求数量。

python 复制代码
import asyncio
import aiohttp
import time

class HttpClientWithSemaphore:
    def __init__(self, max_concurrent_requests=5, request_period=10):
        self.max_concurrent_requests = max_concurrent_requests
        self.request_period = request_period
        self.semaphore = asyncio.Semaphore(max_concurrent_requests)
        self.session = aiohttp.ClientSession()

    async def fetch(self, url):
        async with self.semaphore:
            try:
                async with self.session.get(url) as response:
                    return await response.text()
            except Exception as e:
                print(f"Request failed: {e}")
                return None

    async def close(self):
        await self.session.close()

async def main_with_semaphore():
    client = HttpClientWithSemaphore(max_concurrent_requests=5)
    urls = [
        "http://example.com/api/1",
        "http://example.com/api/2",
        "http://example.com/api/3",
        "http://example.com/api/4",
        "http://example.com/api/5",
        "http://example.com/api/6",
    ]

    tasks = [client.fetch(url) for url in urls]
    responses = await asyncio.gather(*tasks)

    for response in responses:
        if response:
            print(response)

    await client.close()

if __name__ == "__main__":
    asyncio.run(main_with_semaphore())

优点

  • 简单易实现,使用内置的 asyncio.Semaphore 就能限制并发请求数量。
  • 易于维护,代码简单清晰。

缺点

  • 缺少精细的流控机制,例如每 10 秒内限制请求数量(只能控制总并发数量)。
  • 难以适应更加复杂的流控需求。

实现方式 2:使用滑动窗口 (Sliding Window) 算法

滑动窗口算法是一种可以精确控制在一定时间内的请求数量的机制。它能平滑地调整速率。

python 复制代码
import asyncio
import aiohttp
from collections import deque
import time

class SlidingWindowRateLimiter:
    def __init__(self, max_requests, window_seconds):
        self.max_requests = max_requests
        self.window_seconds = window_seconds
        self.timestamps = deque()

    async def acquire(self):
        current_time = time.monotonic()
        # 清理超出窗口时间的旧请求
        while self.timestamps and current_time - self.timestamps[0] > self.window_seconds:
            self.timestamps.popleft()

        if len(self.timestamps) < self.max_requests:
            self.timestamps.append(current_time)
            return True
        else:
            # 计算需要等待的时间
            sleep_time = self.window_seconds - (current_time - self.timestamps[0])
            await asyncio.sleep(sleep_time)
            return await self.acquire()

class HttpClientWithSlidingWindow:
    def __init__(self, max_requests_per_period=5, period=10):
        self.rate_limiter = SlidingWindowRateLimiter(max_requests_per_period, period)
        self.session = aiohttp.ClientSession()

    async def fetch(self, url):
        await self.rate_limiter.acquire()
        try:
            async with self.session.get(url) as response:
                return await response.text()
        except Exception as e:
            print(f"Request failed: {e}")
            return None

    async def close(self):
        await self.session.close()

async def main_with_sliding_window():
    client = HttpClientWithSlidingWindow(max_requests_per_period=5, period=10)
    urls = [
        "http://example.com/api/1",
        "http://example.com/api/2",
        "http://example.com/api/3",
        "http://example.com/api/4",
        "http://example.com/api/5",
        "http://example.com/api/6",
    ]

    tasks = [client.fetch(url) for url in urls]
    responses = await asyncio.gather(*tasks)

    for response in responses:
        if response:
            print(response)

    await client.close()

if __name__ == "__main__":
    asyncio.run(main_with_sliding_window())

优点

  • 更加精确地控制时间窗口内的请求数量。
  • 平滑控制请求速率,适用于需要稳定流量的情况。

缺点

  • 实现稍复杂,需要维护一个请求时间戳队列。
  • 在极端条件下,如果有大量请求积压,可能会造成延迟波动。

实现方式 3:使用 aiolimiter 第三方库

aiolimiter 是一个专门用于异步流控的 Python 库,支持令牌桶和滑动窗口算法。

安装 aiolimiter

bash 复制代码
pip install aiolimiter

代码示例

python 复制代码
import asyncio
import aiohttp
from aiolimiter import AsyncLimiter

class HttpClientWithAiolimiter:
    def __init__(self, max_requests_per_period=5, period=10):
        # 初始化流控器,每10秒允许5个请求
        self.limiter = AsyncLimiter(max_requests_per_period, period)
        self.session = aiohttp.ClientSession()

    async def fetch(self, url):
        async with self.limiter:
            try:
                async with self.session.get(url) as response:
                    return await response.text()
            except Exception as e:
                print(f"Request failed: {e}")
                return None

    async def close(self):
        await self.session.close()

async def main_with_aiolimiter():
    client = HttpClientWithAiolimiter(max_requests_per_period=5, period=10)
    urls = [
        "http://example.com/api/1",
        "http://example.com/api/2",
        "http://example.com/api/3",
        "http://example.com/api/4",
        "http://example.com/api/5",
        "http://example.com/api/6",
    ]

    tasks = [client.fetch(url) for url in urls]
    responses = await asyncio.gather(*tasks)

    for response in responses:
        if response:
            print(response)

    await client.close()

if __name__ == "__main__":
    asyncio.run(main_with_aiolimiter())

优点

  • 使用方便,aiolimiter 直接支持流控机制。
  • 代码简洁且配置灵活,可直接设置流控参数。
  • 第三方库已经过优化,适合快速开发。

缺点

  • 依赖于外部库,需要额外安装。
  • 灵活性相对有限,无法完全控制算法的细节。

比较总结

实现方式 优点 缺点 适用场景
信号量控制 (Semaphore) 简单易实现,易于维护 控制粒度较粗,不适合复杂流控 适合简单并发控制场景
滑动窗口 (Sliding Window) 精确控制时间窗口内的请求数量,平滑控制请求速率 实现稍复杂,可能出现延迟波动 适合需要精确流控的场景
aiolimiter 第三方库 使用方便,代码简洁,库优化良好 依赖外部库,灵活性相对有限 适合快速实现流控的项目

希望这些不同的实现方式和比较能够帮助你选择适合的 HTTP 客户端实现方案。如果你对某种实现方式有特别的需求或疑问,请随时告知!

相关推荐
电商数据girl6 分钟前
有哪些常用的自动化工具可以帮助处理电商API接口返回的异常数据?【知识分享】
大数据·分布式·爬虫·python·系统架构
CoooLuckly9 分钟前
numpy数据分析知识总结
python·numpy
半路_出家ren15 分钟前
传输层协议TCP、UDP
网络协议·tcp/ip·udp·tcp
超龄超能程序猿25 分钟前
(六)PS识别:源数据分析- 挖掘图像的 “元语言”技术实现
python·组合模式
amazinging1 小时前
北京-4年功能测试2年空窗-报培训班学测开-第四十四天
python·学习·appium
UrbanJazzerati1 小时前
Xlwings安装报错:Connection timed out & WinError 32?一招解决你的安装难题!
python
Tipriest_1 小时前
Python异常类型介绍
开发语言·python·异常
前端付豪1 小时前
21、用 Python + Pillow 实现「朋友圈海报图生成器」📸(图文合成 + 多模板 + 自动换行)
后端·python
猿榜2 小时前
魔改编译-永久解决selenium痕迹(二)
javascript·python
广东数字化转型2 小时前
java jar 启动应用程序
开发语言·python