Асинхронное проектирование / реализация - PullRequest
1 голос
/ 08 мая 2019

Я недавно начал реализовывать код async в Python, и у меня есть некоторые сомнения по поводу дизайна и реализации. Например, если мне нужно что-то сделать, позвольте мне вызвать код синхронизации как функцию, отличную от async, и у меня есть только одна функция async, возвращение сопрограммы считается плохой привычкой или плохим дизайном? Позвольте мне объяснить лучше с некоторым кодом:

def my_async_function():
    #some sync code
    return async_code()

вместо:

async def my_async_function():
    #some sync code
    return await async_code()

Как вы думаете, первая версия может скрыть некоторые проблемы?
Или вообще, каждый совет приветствуется, потому что я новичок в этом стиле кода.
П.С .: Извините за мой английский, надеюсь, он понятен.

1 Ответ

0 голосов
/ 08 мая 2019

Оба варианта полностью верны, но если есть сомнения, переходите ко второму. Это сделает кристально ясным для вызывающего абонента, что он имеет дело с сопрограммой, и только сопрограммой.

Существует техническая разница между ними, но она становится очевидной только в том случае, если вызывающая сторона не ожидает ее сразу. Рассмотрим следующий код:

aw = my_async_function()
# ... do something here ...
result = await aw

В вашем первом примере «некоторый код синхронизации» будет запущен, как только вы вызовете функцию, поэтому, если у нее есть побочные эффекты, они будут видны в «сделать что-то здесь». Во втором примере, просто вызывая my_async_function(), совершенно не имеет побочных эффектов, он только создает объект сопрограммы. В этом варианте «некоторый код синхронизации» выполняется только после await aw, т.е. после того, как «сделать что-то здесь» уже выполнено.

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

Хорошо известным примером, который не придерживается этого принципа, является run_in_executor, который немедленно передает вызываемое в пул потоков. По этой причине run_in_executor никогда нельзя сделать действительной сопрограммой, потому что это нарушит код, вызывающий его, не беспокоясь на await (или код, ожидающий только позже, по любой причине).

...