В чем разница между threading и multiprocessing в Python и для каких задач их используют
Что проверяют
Понимаете ли вы роль GIL и умеете ли выбирать по типу нагрузки.
Как отвечать
threading создаёт настоящие потоки внутри одного процесса, память общая. Но GIL позволяет исполнять байт-код только одному потоку одновременно, поэтому вычисления не ускоряются. Зато GIL отпускается на времени ожидания ввода-вывода и внутри C-расширений, поэтому потоки хорошо работают там, где программа ждёт сеть или диск.
multiprocessing запускает отдельные процессы: у каждого свой интерпретатор и свой GIL, значит вычисления реально идут параллельно на разных ядрах. Цена: память на каждый процесс, время запуска и обмен данными через сериализацию (pickle), поэтому передавать большие объекты дорого.
Выбор по задаче:
- ждём сеть или диск, задач много: лучше всего
asyncio, если библиотеки асинхронные, иначе потоки; - считаем: процессы или библиотека, которая сама уходит из-под GIL (NumPy, Polars);
- смешанная нагрузка: пул процессов для расчётов и асинхронность для ввода-вывода.
Удобный общий интерфейс это concurrent.futures с ThreadPoolExecutor и ProcessPoolExecutor: код одинаковый, меняется одна строка.
Полезно упомянуть, что GIL перестаёт быть безусловным: в Python 3.13 появилась сборка без него, но пока экспериментальная и с потерей скорости на однопоточном коде.
Где спотыкаются
Берут потоки для ускорения вычислений.
Считают, что GIL делает потоки бесполезными вообще.
Забывают про стоимость сериализации между процессами и удивляются, что стало медленнее.
Запускают процессы без if __name__ == "__main__" на Windows и получают бесконечное порождение.