реализация промежуточных функций в качестве сопрограмм или возвращение ожидающих - PullRequest
0 голосов
/ 23 февраля 2020

Существует два способа реализации промежуточных функций, которые находятся между созданием Awaitable и сайтом, на котором объект await ed. Одна реализация делает промежуточную функцию сопрограммой, где Awaitable имеет значение await; пользователь тогда await s на этой сопрограмме. Альтернатива - написать промежуточный шаг как функцию, создающую Awaitable и возвращающую его на сайт, где произойдет await. Ниже приведен пример.

import asyncio
from typing import Awaitable


async def wait1() -> None:
    await asyncio.sleep(1)

def wait2() -> Awaitable[None]:
    return asyncio.sleep(1)

async def main():
    await wait1()
    await wait2()

asyncio.run(main())

В чем различия между этими двумя реализациями? Плюсы и минусы? Различия в производительности? Есть ли поведенческие различия? Я нахожусь в состоянии выполнять многие из этих функций и хочу делать «правильные» вещи.

1 Ответ

2 голосов
/ 25 февраля 2020

Как используется в настоящее время, wait1 и wait2 функционально эквивалентны. При вызове оба возвращают объект сопрограммы , то есть результат выполнения асинхронной c (сопрограммы) функции. Различия возникают, если:

  • функции имеют побочные эффекты, а
  • ожидаемое ими возвращение не ожидается немедленно

В этом случае для wait1 побочный эффект произойдет только после того, как его ожидают, а для wait2 он произойдет, как только его вызовут.

В большинстве случаев это не имеет значения, но иногда его можно наблюдать. Например, функция run_in_executor не может быть реализована как сопрограмма, поскольку текущая реализация представляет собой функцию, которая сначала отправляет полученное вызываемое сообщение исполнителю, а затем создает и возвращает asyncio future , который проксирует базовый объект. параллельное будущее . Это позволяет пользователю API писать:

# I don't care about the result, just submit it
loop.run_in_executor(None, my_callback)

Если бы run_in_executor было сопрограммой, это было бы неработоспособно, ничего не было бы отправлено, пока вы либо не дождетесь его, либо не передадите его create_task, чтобы получить он запускается.

Я нахожусь в состоянии сделать много этих функций и хочу сделать "правильную" вещь.

Я бы использовал сопрограммы, где это возможно, просто для ясности. Можно использовать эквивалентность между wait1 и wait2 в местах, где вы не можете использовать сопрограммы, такие как лямбда-выражения.

...