我最近一直在使用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