客户端发送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 客户端实现方案。如果你对某种实现方式有特别的需求或疑问,请随时告知!

相关推荐
ZH15455891311 分钟前
Flutter for OpenHarmony Python学习助手实战:Web开发框架应用的实现
python·学习·flutter
Ekehlaft3 分钟前
这款国产 AI,让 Python 小白也能玩转编程
开发语言·人工智能·python·ai·aipy
开源技术8 分钟前
Python GeoPandas基础知识:地图、投影和空间连接
开发语言·ide·python
hedley(●'◡'●)11 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
Cult Of12 分钟前
Alicea Wind的个人网站开发日志(2)
开发语言·python·vue
啊阿狸不会拉杆17 分钟前
《机器学习导论》第 5 章-多元方法
人工智能·python·算法·机器学习·numpy·matplotlib·多元方法
那就回到过去20 分钟前
MSTP路由协议简介
网络·网络协议·tcp/ip·ensp
wangsir.34 分钟前
测试之自动化测试常用函数
python·测试
铁蛋AI编程实战38 分钟前
MemoryLake 实战:构建超长对话 AI 助手的完整代码教程
人工智能·python·microsoft·机器学习
清水白石00843 分钟前
《为什么说 deque 是 Python 滑动窗口的“隐藏神器”?深入解析双端队列的高效之道》
开发语言·python