⚡️ Что такое coroutine (Сопрограмма) в Python?
Сопрограмма (coroutine) — результат вызова асинхронной функции, представляющий собой выполнение этой функции, способное приостанавливаться. Так как в общем случае невозможно определить сколько раз и на какое время выполнение будет приостановлено, невозможно и сказать когда оно будет закончено. Ваш код может либо ждать завершения выполнения сопрограммы с помощью оператора await, либо поручить ожидание циклу событий и продолжить свой выполнение.
В первом случае
выполнение caller приостановится до выполнения callee. В этот момент какие-то другие операции в каких-то других сопрограммах могут продолжаться, но
Во втором случае
caller сразу же продолжит свою работу. Строка
Но что если, callee будет возвращать какое-то значение, которое нужно вызывающей стороне, но не прямо сейчас, а когда будет готово? Вот тут-то на сцену выходят футуры.
Футура (Future) - будущий результат выполнения сопрограммы. Метод
Или может заняться своими делами, периодически проверяя готовность
Или может собрать их в список и ждать все. Или не все, а только ту, которая будет выполнена первой, а остальные проигнорировать. Или передать футуру другой сопрограмме, а самой заняться каким-нибудь другим делом. В общем, это "очень полезный горшок, куда можно класть какие хочешь вещи".
Осталось только разобраться, чем отличаются футуры от задач. Ничем не отличаются, по большому счёту. Класс
Подытоживая: Task - это задача, поставленная циклу событий, на выполнение
@python_job_interview
Сопрограмма (coroutine) — результат вызова асинхронной функции, представляющий собой выполнение этой функции, способное приостанавливаться. Так как в общем случае невозможно определить сколько раз и на какое время выполнение будет приостановлено, невозможно и сказать когда оно будет закончено. Ваш код может либо ждать завершения выполнения сопрограммы с помощью оператора await, либо поручить ожидание циклу событий и продолжить свой выполнение.
В первом случае
async def callee():
print('Hello')
async def caller():
await callee()
print('World')
выполнение caller приостановится до выполнения callee. В этот момент какие-то другие операции в каких-то других сопрограммах могут продолжаться, но
caller
будет ждать там, где выполнил await
.Во втором случае
async def callee():
print('Hello')
async def caller():
asyncio.create_task(callee())
print('World')
caller сразу же продолжит свою работу. Строка
"World"
будет выведена раньше, чем "Hello".
Здесь мы видим, что caller поставил циклу событий задачу выполнить сопрограмму callee.Но что если, callee будет возвращать какое-то значение, которое нужно вызывающей стороне, но не прямо сейчас, а когда будет готово? Вот тут-то на сцену выходят футуры.
Футура (Future) - будущий результат выполнения сопрограммы. Метод
ensure_future
поручает циклу событий выполнить сопрограмму и сразу же, в момент вызова, возвращает футуру, в которой будет значение, но неизвестно когда. Вызывающая сторона может подождать выполнения футуры так же, как ожидало саму сопрограмму
async def callee():
return 'Hello'
async def caller():
loop = asyncio.get_event_loop()
future = loop.ensure_future(callee())
result = await future
print(result + ' World')
Или может заняться своими делами, периодически проверяя готовность
async def caller():
loop = asyncio.get_event_loop()
future = loop.ensure_future(callee())
while not future.done():
# Какие-нибудь циклические дела
print(future.result() + ' World')
Или установить на футуру колбэк
async def caller():
loop = asyncio.get_event_loop()
future = loop.ensure_future(callee())
future.add_done_callback(lambda f: print(f.result() + ' World'))
# какие-нибудь другие важные дела
Или может собрать их в список и ждать все. Или не все, а только ту, которая будет выполнена первой, а остальные проигнорировать. Или передать футуру другой сопрограмме, а самой заняться каким-нибудь другим делом. В общем, это "очень полезный горшок, куда можно класть какие хочешь вещи".
Осталось только разобраться, чем отличаются футуры от задач. Ничем не отличаются, по большому счёту. Класс
Task
- это наследник класса Future
. А существенная разница между asyncio.create_task() и loop.ensure_future()
только в том, что первой не было до Python 3.7.Подытоживая: Task - это задача, поставленная циклу событий, на выполнение
coroutine
, одновременно являющаяся Future
, которая представляет собой результат выполнения Task
когда-нибудь в будущем.@python_job_interview