【发布时间】:2019-05-25 05:19:25
【问题描述】:
我正在尝试从异步函数中的函数中获取收益。花了几个小时试图弄清楚这一点并遍历 Stack Overflow 以找到以前回答但无法帮助我找到解决自己问题的类似问题,我发现自己在这里。
很简单,我想使用 Web 浏览器和 Websockets 通过 Panoramisk 查询 Asterisk 管理界面。当用户连接到 websocket 服务器时,它会运行 ws_handle 方法
async def ws_handle(websocket, path):
await register(websocket)
try:
async for message in websocket:
data = json.loads(message)
...
然后我想检索一些数据,然后交付给客户端。我遇到的问题是我发现我无法说出来
exts = yield from ExtensionStateList.get(AmiManager)
ExtensionStateList.get 函数的位置(大致)如下:
def get(AmiManager):
queues_details = yield from AmiManager.send_action(
{'Action': 'ExtensionStateList'})
...
val = {
'extensions': EXTENSIONS,
'parks': PARKS,
'paging': PAGING,
'confrences': CONFRENCES,
'apps': APPS,
'misc': MISC
}
return val
我在另一个与我的 websockets 服务器文件分开的测试文件中使用了同一个文件 ExtensionStateList.py,以非异步方法调用它,如前所示
exts = yield from ExtensionStateList.get(AmiManager)
没有问题,它使用函数返回的值填充 exts。
我的研究让我像这样迭代它:
async for a in ExtensionStateList.get(AmiManager):
yield a
但我不知道如何使用它来填充我希望填充的变量。我试过这样:
exts = ''
async for a in ExtensionStatList.get(AmiManager):
exts = exts+a
只是被告知它不能将 AsyncIO.Future 加入到字符串中。我还尝试将return val 换成yield val,但还是没有成功。
显然,对我来说,这是我缺乏 Python 知识的一个缺点。我能做些什么?我在想也许我可以将 ExtensionStateList.get 更改为 async,但这会让我回到我现在所处的同一条船上?
额外
我继续翻遍StackOverflow,发现如下问题:
What is the difference between @types.coroutine and @asyncio.coroutine decorators?
在我看来,也许如果我在ws_handle 上方的行上添加@asyncio.coroutine,就像这样:
@asyncio.coroutine
async def ws_handle(websocket, path):
我将能够:
exts = yield from ExtensionStateList.get(AmiManager)
但是,我发现这不起作用,它告诉我无法从异步函数内部产生。我是否误解了我在这里阅读的内容?或者我可能没有正确实施它?我在这方面走在正确的轨道上吗?
根据这里给出的答案:
'yield from' inside async function Python 3.6.5 aiohttp
我也尝试过像这样等待函数:
exts = await ExtensionStateList.get(AmiManager)
但是,Python 告诉我对象生成器不能用于 await 表达式。
更多
对于那些可能感兴趣的人,这就是我调用 ws_handle 函数的方式。它在创建 websocket 服务器时被调用,websocket 服务器负责调度/调用? ws_handle 函数。
在我看来,它为每个连接的客户端调用一次这个函数,这个函数一直运行到用户断开连接。
WebsocketServer = websockets.serve(ws_handle, host, port)
asyncio.get_event_loop().run_until_complete(WebsocketServer)
asyncio.get_event_loop().run_forever()
附录
是的,我再次添加更多内容。我已经修改了我的 ExtensionStateList.py,以便在调用 get 方法时,它按以下方式执行:
async def get(AmiManager):
val = await getInternal(AmiManager)
return val
@asyncio.coroutine
def getInternal(AmiManager):
我现在可以在 getInternal 函数内部使用yield from,这以前是我的 get 函数,我可以调用它并按以下方式接收日期:
exts = await ExtensionStateList.get(AmiManager)
我想我已经掌握了这一点,并且我看到了它们是如何以两种不同的方式来做几乎相同的事情。
感谢你们为我指明了正确的方向!
【问题讨论】:
-
AmiManager中有什么异步的吗?如果没有,只需将其用作常规(非异步)生成器。但是,如果它正在执行任何 I/O,您可能需要查看run_in_executor之类的内容,以防止它阻塞其他 I/O。 -
是的,AmiManager 指的是 Panoramisk(如果你是农家的话)。它确实是异步运行的,我必须使用 yield from 来检索结果。作为参考,我将在我的问题中添加更多关于我如何调用循环的细节。
标签: python python-3.x websocket python-asyncio yield-from