Первой появится f2: её длинный цикл не содержит await и блокирует event loop. Даже если секунда сна f1 уже прошла, f1 не сможет продолжиться, пока f2 не отдаст управление.
Определение последовательности вывода при использовании asyncio.gather
Первой появится f2: её длинный цикл не содержит await и блокирует event loop. Даже если секунда сна f1 уже прошла, f1 не сможет продолжиться, пока f2 не отдаст управление.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Какой вывод появится в консоли первым и почему?
import asyncio
async def f1():
await asyncio.sleep(1)
print("f1")
async def f2():
for _ in range(1_000_000_000):
pass
print("f2")
async def main():
await asyncio.gather(f1(), f2())
asyncio.run(main())
Ответ
Первой появится f2: её длинный цикл не содержит await и блокирует event loop. Даже если секунда сна f1 уже прошла, f1 не сможет продолжиться, пока f2 не отдаст управление.
gather планирует обе корутины, но не превращает CPU-работу в параллельное выполнение. f1 начинает sleep и уступает управление; f2 крутит цикл до конца и печатает f2. Затем f1 получает возможность напечатать f1.
Если цикл неожиданно займёт меньше секунды, f1 просто дождётся остатка таймера, порядок останется тем же. CPU-тяжёлую работу обычно выносят в процесс или специализированный исполнитель. Само добавление async к функции не делает её неблокирующей.