Короткий ответ Обычный вызов функции выполняется сразу и полностью в текущем потоке управления; await на корутине передаёт управление циклу событий, позволяя другим задачам выполняться во время ожидания. Как это работает подробнее Вызов foo() — прямая передача управления в её тело и возврат результата по завершении, без возможности «уступить» выполнение чему-то ещё. await coro — явная точка приостановки: пока корутина ждёт (например, I/O), цикл может переключиться на другие готовые корутины. Пример кода Что использовать на практике Практика. await можно использовать только внутри async def функции; обращение к корутине без await не выполняет её тело — создаётся объект корутины, который нужно либо await-нуть, либо передать в asyncio.create_task/gather. Подводные камни Риски. Пытаются использовать await вне async-функции (SyntaxError); ожидают, что await сам по себе даёт параллелизм для CPU-bound кода — выгода есть только если ожидаемая операция реализует неблокирующее ожидание.