Как вызвать асинхронную функцию в коде синхронизации и разорвать цепочку асинхронности/ожидания (т. Е. Как обернуть асинхронную функцию в функцию синхронизации)

#python #async-await #python-asyncio

Вопрос:

Весь мой код написан без учета asyncio; однако я использую одну асинхронную функцию (написанную другим разработчиком; для моих целей это черный ящик). Давайте назовем это func_1 . Мне нужно вызвать эту функцию изнутри другой функции, вызвать ее func_2 (которая сама по себе может быть вызвана в произвольно длинной цепочке функций func_3 и func_4 т. Д.).

Поскольку func_1 это асинхронно, мне нужно его дождаться, но так как я его вызываю func_2 , мне также нужно выполнить func_2 асинхронность (я не могу ждать в несинхронной функции). И это продолжается; мне нужно превратить всю цепочку функций func_2 func_3 func_4 в асинхронные функции.

Есть ли способ избежать этого? Я просто хочу позвонить func_1 , дождаться его завершения и использовать результаты в остальной части моего обычного кода на python. Могу ли я создать оболочку, func_1 чтобы разрешить это?

То, что я хочу, по сути, заключается в следующем, что не работает:

 # This is the function defined by someone else
async def func_1(*args):
    return something(*args)

# This is my wrapper
def func_1_wrapper(*args):
    return await func_1(*args)

# So that I can call it like normal within the rest of my code
def func_2(*args):
    # do something
    a = func_1_wrapper(*args)
    # do something else
 

Комментарии:

1. Вы можете выполнить func_1 вход func_1_wrapper и дождаться его завершения с помощью asyncio.run : asyncio.run(func_1())

2. Если вы заботитесь о том, чтобы он был асинхронным, потому что он позволяет (псевдо) параллельное выполнение кода , тогда да, вам нужно сделать все await и async полностью. Если нет, и вы не против func_1 заблокировать все, пока это не будет сделано, просто asyncio.run(func_1()) .

3. Верно, звучит намного проще, чем я ожидал. Единственное, чего у меня нет asyncio.run в моей версии пакета. Кстати , у моего asyncio нет asyncio.__version__ , что меня удивляет. run_coroutine_threadsafe Сделал бы то же самое?

4. В более старых версиях вы бы использовали asyncio.get_event_loop().run_until_complete(func_1()) .

5. Я предполагаю , что в стандартных библиотечных пакетах нет __version__ , я об этом не знал. Так что это похоже на python 3.6.5.