Вызов корутины синхронно

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

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

пример:

async def complicated_func():
    foo()
    bar()
    await baz()

после:

async def complicated_func():
    foo()
    await extracted_func()

async def extracted_func():
    bar()
    await baz()

в Примере ранее,complicated_func гарантированно не будет приостановлено между вызовами foo(), а вызов bar(). После рефакторинга, эта гарантия теряется.

мой вопрос заключается в следующем: можно ли позвонить extracted_func() такой, что он выполняется немедленно, как если бы его код был встроенным? Или есть какой-то другой способ выполнить такие распространенные задачи рефакторинга без изменения семантики программ?

1 ответов


после рефакторинга, эта гарантия теряется.

на самом деле нет.

можно ли вызвать extracted_func () таким образом, чтобы он выполнялся немедленно, как если бы его код был встроенным?

это уже дело.

await some_coroutine() означает, что some_coroutine скорее всего, вернет управление циклу событий, но он не будет этого делать, пока он фактически не ждет будущего (e.g некоторые операции ввода-вывода операция.)

Рассмотрим пример:

import asyncio

async def coro():
    print(1)
    await asyncio.sleep(0)
    print(3)

async def main():
    loop.call_soon(print, 2)
    await coro()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

обратите внимание, как 2 печатается между 1 и 3 как и ожидалось.

это также означает, что можно заморозить цикл событий, написав такой код:

async def coro():
    return

async def main():
    while True:
        await coro()

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