python – aiohttp:限制并行请求的速率

API通常具有用户必须遵循的速率限制.举个例子,我们需要50个请求/秒.顺序请求需要0.5-1秒,因此太慢而不能接近该限制.但是,使用aiohttp的并行请求超出了速率限制.

要以尽可能快的速度轮询API,需要对并行调用进行速率限制.

到目前为止我找到的示例装饰了session.get,大致如下:

session.get = rate_limited(max_calls_per_second)(session.get)

这适用于顺序调用.尝试在并行调用中实现此功能并不按预期工作.

以下是一些代码示例:

async with aiohttp.ClientSession() as session:
    session.get = rate_limited(max_calls_per_second)(session.get)
    tasks = (asyncio.ensure_future(download_coroutine(  
          timeout, session, url)) for url in urls)
    process_responses_function(await asyncio.gather(*tasks))

这样做的问题是它会对任务的排队进行速率限制.使用聚集执行仍然会或多或少同时发生.最糟糕的两个世界;-).

是的,我在aiohttp: set maximum number of requests per second找到了一个类似的问题,但是没有回复回答限制请求率的实际问题.此外,the blog post from Quentin Pradet仅适用于限速排队.

包装起来:如何限制并行aiohttp请求的每秒请求数?

解决方法:

如果我理解你,你想限制同时请求的数量?

asyncio中有一个名为Semaphore的对象,它的工作方式与异步RLock类似.

semaphore = asyncio.Semaphore(50)
#...
async def limit_wrap(url):
    async with semaphore:
        # do what you want
#...
results = asyncio.gather([limit_wrap(url) for url in urls])

更新

假设我发出了50个并发请求,它们都在2秒内完成.因此,它没有触及限制(每秒只有25个请求).

这意味着我应该发出100个并发请求,它们也都在2秒内完成(每秒50个请求).但在你真正提出这些要求之前,你怎么能确定它们会完成多长时间?

或者,如果您不介意每秒完成的请求,而是每秒发出的请求.您可以:

async def loop_wrap(urls):
    for url in urls:
        asyncio.ensure_future(download(url))
        await asyncio.sleep(1/50)

asyncio.ensure_future(loop_wrap(urls))
loop.run_forever()

上面的代码将每1/50秒创建一个Future实例.

上一篇:python – asyncio web scraping 101:使用aiohttp获取多个url


下一篇:python – 使用Aiohttp与代理