Python 3.x 如何在Python3异步IO中实现同步等待回调?

Python 3.x 如何在Python3异步IO中实现同步等待回调?,python-3.x,python-asyncio,aiohttp,Python 3.x,Python Asyncio,Aiohttp,由于一些不寻常的限制,我需要在返回响应之前同步等待来自另一个服务的回调URL。目前我有一些类似于: ROUTE = '/operation' async def post(self): ##SOME OPERATIONS## post_body = { 'callbackUrl' : 'myservice.com/cb' } response = await other_service.post('/endpoint') global my_return_valu

由于一些不寻常的限制,我需要在返回响应之前同步等待来自另一个服务的回调URL。目前我有一些类似于:

ROUTE = '/operation'
async def post(self):
    ##SOME OPERATIONS##
    post_body = { 'callbackUrl' : 'myservice.com/cb' }
    response = await other_service.post('/endpoint')
    global my_return_value
    my_return_value = None
    while not my_return_value:
        pass
    return self.make_response(my_return_value)
然后我有了一种处理回调URL的方法,类似于:

ROUTE = '/cb'
async def post(self):
    ##OPERATIONS###
    global my_return_value
    my_return_value = some_value
    return web.json_response()
这段代码的问题是,即使调用了回调URL,它也会永远陷入while循环。我怀疑有更好的方法可以做到这一点,但我不知道如何去做,也不知道如何用谷歌搜索。有什么想法吗


提前谢谢

只是快速扫描一下,但我想你被困在

while not my_return_value:
    pass
Python将被困在那里,没有时间处理回调函数。你需要的是

while not my_return_value:
    await asyncio.sleep(1)
如果不需要毫秒延迟,甚至可以执行asyncio.sleep0

更好的方式是,现在我凭记忆写作,不保证…:

my_return_value = asyncio.get_event_loop().create_future()
await my_return_value
return self.make_response(my_return_value.result())


async def post(self):
    ##OPERATIONS###
    my_return_value.set_result(some_value)
    return web.json_response()
但是,请注意,如果此系统有多个并发使用,则任何一种方法都会非常失败。感觉很脆弱!也许更好:

ROUTE = '/operation'
my_return_value = {}

async def post(self):
    ##SOME OPERATIONS##
    token = "%016x" % random.SystemRandom().randint(0, 2**128)
    post_body = { 'callbackUrl' : 'myservice.com/cb?token='+token }
    response = await other_service.post('/endpoint')
    my_return_value[token] = asyncio.get_event_loop().create_future()
    await my_return_value[token]
    result = my_return_value[token].result()
    del my_return_value[token]
    return self.make_response(result)

async def post(self):
    ##OPERATIONS###
    token = self.arguments("token")
    my_return_value[token].set_result(some_value)
    return web.json_response()

现在,上面的cherry将是一个计时器,它将在超时后取消未来,并在一段时间后清除my_return_值中的条目(如果回调没有发生)。另外,如果你同意我的上一个建议,不要称之为my_return_值,而是像callback_future_by_token…

这样做可能有更好的方法,但我认为你眼前的问题是,你在回调路径中丢失了一个全局my_return_值。那么为什么不使用其他服务呢,web.json_response tuple?调用post后,您将设置my_return_value=None,从而得到一个无限循环。您的协同例程仍然是连续的,/operation post协同例程将不会继续,直到response=wait other_service.post'/endpoint'返回。@MartijnPieters我相信另一个_service.post。。。调用发出HTTP请求,然后返回,而在另一个服务返回并向我们发出HTTP请求之前,不会调用回调。@smarx这是正确的。我当前的解决方案与您的第二个解决方案类似,只是用uuid代替了随机数生成。不过,我对未来的使用没有那么自信,所以这特别有帮助。