Невозможно получить изнутри асинхронную функцию и получить данные - PullRequest
0 голосов
/ 27 декабря 2018

Я пытаюсь получить из функции внутри асинхронной функции.Потратив часы на то, чтобы выяснить это и обойти переполнение стека, чтобы найти похожие вопросы, на которые уже были даны ответы, но не смог помочь мне найти решение своей проблемы, я попал сюда.

Проще говоря, я хочу запроситьИнтерфейс управления Asterisk через Panoramisk, используя веб-браузер и веб-сокеты.Когда пользователь подключается к серверу 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

У меня естьиспользовал этот же файл ExtensionStateList.py в другом тестовом файле, отдельном от моего файла сервера websockets, в неасинхронном методе, вызывая его, как показано выше,

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 на асинхронный, но это отбросило бы меня обратно в ту же лодку, в которой я сейчас нахожусь?

ДОПОЛНИТЕЛЬНО

У меня естьпродолжил поиск в StackOverflow и нашел следующий вопрос:

В чем разница между декораторами @ types.coroutine и @ asyncio.coroutine?

Мне кажется, чтовозможно, если я добавлю @asyncio.coroutine в строке выше ws_handle, например, так:

@asyncio.coroutine
async def ws_handle(websocket, path):

, что я тогда смогу:

exts = yield from ExtensionStateList.get(AmiManager)

Однако я нахожу, что этоне работает, и это говорит мне, что я не могу дать изнутри асинхронной функции.Я неправильно понимаю, что я читаю здесь?Или я, может быть, не правильно его реализую?Я на правильном пути с этим?

Согласно ответу, приведенному здесь:

'yield from' внутри асинхронной функции Python 3.6.5 aiohttp

Я также пытался дождаться функции следующим образом:

exts = await ExtensionStateList.get(AmiManager)

Однако Python сообщает мне, что генератор объектов нельзя использовать в выражении ожидания.

FURTHERMORE

Для тех, кого это может заинтересовать, так я вызываю свою функцию ws_handle.Он вызывается при создании сервера веб-сокетов, и сервер веб-сокетов отвечает за отправку / вызов? функции ws_handle.

Мне кажется, что он вызывает эту функцию один раз для каждого клиентакто подключается, и эта функция работает до тех пор, пока пользователь не отключится.

WebsocketServer = websockets.serve(ws_handle, host, port)
asyncio.get_event_loop().run_until_complete(WebsocketServer)
asyncio.get_event_loop().run_forever()

ADDENDUM

Да, снова я добавляю еще больше.Я изменил свой ExtensionStateList.py, чтобы при вызове метода get он выполнялся следующим образом:

async def get(AmiManager):
    val = await getInternal(AmiManager)
    return val

@asyncio.coroutine
def getInternal(AmiManager):

Теперь я могу использовать yield from внутри функции getInternal, которая ранее была моей функцией getи я могу позвонить и получить дату, как показано ниже:

exts = await ExtensionStateList.get(AmiManager)

Мне кажется, я это понимаю, и я вижу, как это два разных способа сделать почти одно и то же.

Спасибо, что указали мне правильное направление, ребята!

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Вас немного смущает изменение синтаксиса asyncio.В 3.5 мы перешли на async def и ждем. Подробности см. В этом ответе и обратите внимание на приведенный ниже пример:

Требуется асинхронный генератор.См. Pep 525 и пример кода:

async def ticker(delay, to):
    """Yield numbers from 0 to `to` every `delay` seconds."""
    for i in range(to):
        yield i
        await asyncio.sleep(delay)
0 голосов
/ 27 декабря 2018

Держите мысль - я не понял это.Согласно моему комментарию ниже, я, должно быть, устал, и принял ошибку за работу программы.Упс.

EUREKA!

После нескольких часов рвать волосы, читать документацию и почти слезы я обнаружил, что @async.coroutine необходимо применить к методу ExtensionStateList.get следующим образом:

#In ExtensionStateList.py
@asyncio.coroutine
def get(AmiManager):

и что я должен ждать при вызове этой команды следующим образом:

exts = ExtensionStateList.get(AmiManager)
await exts

Я обнаружил, что если я только await exts, не сделав его asyncio.coroutine, он вернет ошибкузаявив, что вы не можете ждать генератора.

...