Чем корутина в Python отличается от обычной функции

Ответ

Основное отличие заключается в том, что корутина может приостанавливать свое выполнение и передавать управление обратно в цикл событий (event loop), не завершаясь. Обычная функция выполняется от начала до конца без пауз.

Это позволяет корутинам выполнять длительные операции ввода-вывода (I/O) без блокировки всего потока выполнения, что является основой асинхронного программирования.

Сравнительная таблица

Характеристика Обычная функция Корутина (async def)
Выполнение Синхронное, блокирующее Асинхронное, неблокирующее
Приостановка Не может быть приостановлена Может быть приостановлена с помощью await
Возврат значения Возвращает результат через return При вызове возвращает объект корутины, который нужно запустить
Основное применение Вычисления, блокирующие операции I/O-bound задачи (сетевые запросы, работа с БД)

Пример

Сравним блокирующую функцию и неблокирующую корутину, которые ждут 1 секунду.

Обычная (блокирующая) функция:

import time

def blocking_task():
    print("Blocking task started...")
    time.sleep(1) # Блокирует весь поток на 1 секунду
    print("Blocking task finished.")

# Вызов
blocking_task()

Корутина (неблокирующая):

import asyncio

async def non_blocking_task():
    print("Non-blocking task started...")
    # await передает управление event loop, позволяя выполнять другие задачи
    await asyncio.sleep(1) 
    print("Non-blocking task finished.")

# Для запуска корутины нужен event loop
asyncio.run(non_blocking_task())

Ключевое слово await внутри корутины говорит: "эта операция может занять время, я подожду, а ты, event loop, пока займись другими делами".

Ответ 18+ 🔞

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

Это, сука, и есть магия асинхронщины: корутины позволяют ждать ввода-вывода (типа запроса к базе или API), не блокируя весь поток, чтобы остальные задачи не стояли в очереди, как дураки.

Табличка для наглядности, а то мозги заплыли

Признак Обычная функция Корутина (async def)
Как работает Синхронно, блокирует всё, пока не кончит Асинхронно, умеет ждать без блокировки
Можно ли приостановить Ни хуя, только завершить Да, с помощью await
Что возвращает Результат сразу через return Объект-обещание (корутину), который надо запустить
Где юзают Для вычислений, где не надо ждать Для I/O операций (сеть, файлы, БД)

Пример, чтобы совсем пиздец стало понятно

Сравним, как обычная функция и корутина ждут одну секунду. Разница — как между стоять в очереди в ЖЭКе и ждать доставку еды дома.

Обычная функция (блокирует всё, как говно в трубе):

import time

def blocking_task():
    print("Blocking task started...")
    time.sleep(1) # Здесь весь поток встаёт колом на секунду, блядь
    print("Blocking task finished.")

# Вызов
blocking_task()

Корутина (неблокирующая, хитрая жопа):

import asyncio

async def non_blocking_task():
    print("Non-blocking task started...")
    # await говорит: "Я подожду, а ты, event loop, иди другие дела делай"
    await asyncio.sleep(1) 
    print("Non-blocking task finished.")

# Корутину нельзя просто так вызвать, нужен event loop
asyncio.run(non_blocking_task())

Вот и вся магия, ёпта. Ключевое слово await — это как фраза «я отлучился, не худей». Оно передаёт управление обратно в цикл событий, чтобы тот мог пока другие корутины погонять. А обычная функция — это как болт: закрутился и не остановишь, пока не довернёшь до конца.