Ответ
Основное отличие заключается в том, что корутина может приостанавливать свое выполнение и передавать управление обратно в цикл событий (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, пока займись другими делами".