如何在 Python 3 asyncio 中实现同步等待回调?
How do I implement synchronously waiting for a callback in Python 3 asyncio?
由于一些不寻常的限制,我需要在返回响应之前同步等待来自另一个服务的回调 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()
此代码的问题在于它永远陷入 while 循环,即使回调 URL 被调用也是如此。我怀疑有更好的方法可以做到这一点,但我不确定如何去做,也不知道如何 google 。有什么想法吗?
提前致谢!
只是快速浏览一下,但我认为你被困在了
while not my_return_value:
pass
Python会被困在那里没时间处理回调函数。你需要的是
while not my_return_value:
await asyncio.sleep(1)
(或者,如果您不想延迟毫秒,您甚至可以执行 asyncio.sleep(0)
)。
更好的方法是(现在我是凭记忆写的,不能保证...):
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 on top 将是一个计时器,它会在超时后取消 future 并在一段时间后如果回调没有发生则清理 my_return_value
中的条目。此外,如果您接受我最后的建议,请不要将其命名为 my_return_value
,而应命名为 callback_future_by_token
...
由于一些不寻常的限制,我需要在返回响应之前同步等待来自另一个服务的回调 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()
此代码的问题在于它永远陷入 while 循环,即使回调 URL 被调用也是如此。我怀疑有更好的方法可以做到这一点,但我不确定如何去做,也不知道如何 google 。有什么想法吗?
提前致谢!
只是快速浏览一下,但我认为你被困在了
while not my_return_value:
pass
Python会被困在那里没时间处理回调函数。你需要的是
while not my_return_value:
await asyncio.sleep(1)
(或者,如果您不想延迟毫秒,您甚至可以执行 asyncio.sleep(0)
)。
更好的方法是(现在我是凭记忆写的,不能保证...):
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 on top 将是一个计时器,它会在超时后取消 future 并在一段时间后如果回调没有发生则清理 my_return_value
中的条目。此外,如果您接受我最后的建议,请不要将其命名为 my_return_value
,而应命名为 callback_future_by_token
...