Как работают потоки в Python
Что проверяют
Понимаете ли вы роль GIL и знаете ли, где потоки всё-таки полезны.
Как отвечать
threading создаёт настоящие потоки операционной системы, они делят память процесса. Но интерпретатор CPython защищён глобальной блокировкой (GIL): байт-код одновременно выполняет только один поток.
Отсюда главное следствие: потоки не ускоряют вычисления. Два потока, считающие числа, работают не быстрее одного, а иногда медленнее из-за переключений.
Где потоки полезны: там, где программа ждёт. GIL отпускается на время операций ввода-вывода (сеть, диск), при вызове time.sleep и внутри многих C-расширений, включая NumPy. Поэтому сто потоков, качающих страницы, работают заметно быстрее последовательного кода.
Что важно знать помимо этого:
- гонки никуда не деваются: GIL защищает внутренние структуры интерпретатора, а не вашу логику.
counter += 1из двух потоков теряет инкременты, потому что это три операции; - инструменты:
threading.Lock,RLock,Event,Condition,Semaphore, а лучшеqueue.Queue, которая потокобезопасна и снимает необходимость в ручных блокировках; - пул:
ThreadPoolExecutorвместо ручного создания потоков; - демоны: поток-демон не мешает процессу завершиться, обычный держит его до конца.
Альтернативы: asyncio для тысяч одновременных ожиданий (дешевле потоков), multiprocessing для вычислений. В Python 3.13 появилась экспериментальная сборка без GIL, но пока с потерей однопоточной скорости.
Где спотыкаются
Берут потоки для ускорения расчётов.
Считают, что GIL избавляет от гонок.
Не знают, что GIL отпускается на вводе-выводе, и объявляют потоки бесполезными.
Создают поток на каждую задачу вместо пула.