В чем разница async и threads
Что проверяют
Понимаете ли вы, как устроены обе модели в CPython и какую задачу какой решать. Следом почти наверняка спросят про GIL и про то, что будет, если внутри корутины вызвать блокирующую функцию.
Как отвечать
Главное различие в том, кто переключает задачи:
- потоки (
threading): настоящие потоки ОС, их переключает планировщик системы в любой момент, это вытесняющая многозадачность. Данные общие, поэтому нужныthreading.Lock,queue.Queueи аккуратность с гонками; - async (
asyncio): один поток и цикл событий, кооперативная многозадачность. Корутина отдаёт управление только в точкеawait, поэтому гонок меньше, но между двумяawaitсостояние всё равно может поменяться.
Про GIL. В обычной сборке CPython байткод Python в каждый момент исполняет только один поток, поэтому потоки не ускоряют CPU-bound код. GIL отпускается на блокирующем вводе-выводе и в части C-расширений, так что для I/O потоки работают нормально. Для вычислений берут multiprocessing или ProcessPoolExecutor. В Python 3.13 появилась экспериментальная сборка без GIL, в 3.14 она официально поддерживается, но по умолчанию не используется, и не все библиотеки к ней готовы.
Когда что выбирать:
- asyncio: много одновременных сетевых соединений, веб-сокеты, FastAPI. Корутина дешевле потока ОС, их держат десятками тысяч. Нужны асинхронные библиотеки:
httpx,aiohttp,asyncpg; - потоки: немного параллельных I/O-задач с синхронными библиотеками, например
requestsили старым драйвером базы, черезThreadPoolExecutor; - связка: блокирующий вызов из асинхронного кода уводят в поток через
asyncio.to_thread().
Где спотыкаются
Говорят, что потоки в Python подходят для CPU-bound задач и загружают все ядра. В обычном CPython из-за GIL это не так.
Вызывают time.sleep() или requests.get() внутри async def. Цикл событий блокируется целиком, и все остальные корутины стоят, пока вызов не вернётся.
Считают, что async сам по себе делает код быстрее. Он помогает, только когда программа много ждёт ввода-вывода. Ещё частая ошибка: вызвать корутину без await. Она не выполнится, а Python выдаст предупреждение coroutine ... was never awaited.