在asyncio中强制执行串行请求

时间:2017-09-19 00:20:50

标签: python rest http python-requests

我最近一直在使用asyncio和http请求包aiohttp而且我遇到了问题。

我的应用程序与REST API进行对话。

对于某些API端点,能够并行分派多个请求是有意义的。例如。将请求中的不同查询发送到同一端点以获取不同的数据。

虽然对某些终端来说,这没有意义。在端点中始终采用相同的参数(身份验证)并返回所请求的信息。 (在服务器响应一次之前,没有必要多次询问相同的数据)对于这些端点,我需要强制执行“串行”请求流。因为我的程序应该只能在不等待响应时发送请求。 (阻止请求的典型行为)。

当然我不想阻止。

这是我打算做的事情的抽象。基本上将endpoint包装在异步生成器中,以强制执行此串行行为。

我觉得我正在重新发明轮子,这个问题是否有共同的解决方案?

import asyncio
from time import sleep

# Encapsulate the idea of an endpoint that can't handle multiple requests
async def serialendpoint():
    count = 0
    while True:
        count += 1
        await asyncio.sleep(2)
        yield str(count)


# Pretend client object
class ExampleClient(object):
    gen = serialendpoint()

    # Simulate a http request that sends multiple requests
    async def simulate_multiple_http_requests(self):
        print(await self.gen.asend(None))
        print(await self.gen.asend(None))
        print(await self.gen.asend(None))
        print(await self.gen.asend(None))

async def other_stuff():
    for _ in range(6):
        await asyncio.sleep(1)
        print('doing async stuff')

client = ExampleClient()

loop = asyncio.get_event_loop()

loop.run_until_complete(asyncio.gather(client.simulate_multiple_http_requests(), 
                                       client.simulate_multiple_http_requests(), 
                                       other_stuff()))

输出

doing async stuff
1
doing async stuff
doing async stuff
2
doing async stuff
doing async stuff
3
doing async stuff
4
5
6
7
8

更新

这是我实现的实际异步生成器:

在导入阶段,所有需要串行行为的端点都会被分配serial_request_async_generator。这意味着我无法用await 'async_gen'.asend(None)初始化它们,因为await只允许在异步协程中使用。折衷方案是运行时的每个串行请求必须在.asend(None)实际参数之前asend。必须有更好的方法!

async def serial_request_async_generator():
    args, kwargs = yield
    while True:
        yield await request(*args, **kwargs)  # request is an aiohttp request
        args, kwargs = yield

0 个答案:

没有答案