Параллелизм: Многопроцессность
Задействуйте все ядра процессора, запуская настоящие отдельные процессы Python
multiprocessing запускает ваш код в отдельных процессах операционной системы, у каждого из которых свой интерпретатор Python и своя глобальная блокировка интерпретатора (GIL). Это единственный надёжный способ заставить CPU-bound (нагруженный вычислениями) код Python работать сразу на многих ядрах. Плата за это в том, что процессы не разделяют память, поэтому каждый аргумент и каждый результат должны быть сериализованы (pickle) и переправлены через границу процесса.
- объяснить, почему GIL заставляет использовать процессы (а не потоки) для вычислительной работы,
- запускать задачи через
Process,PoolиProcessPoolExecutor, - выбирать между
map,imapиapply_asyncи подбирать разумныйchunksize, - передавать данные с помощью
Queue,Pipeиshared_memory, - избегать классических ловушек: защита
if __name__ == "__main__", несериализуемые аргументы и методы запуска (spawnпротивfork).
1. GIL и почему потоки не ускоряют вычисления
CPython защищает своё внутреннее состояние глобальной блокировкой интерпретатора (GIL): в любой момент только один поток может выполнять байт-код Python. Для I/O-bound работы (ожидание сети, диска или базы данных) потоки прекрасны, потому что поток освобождает GIL, пока ждёт. Но для CPU-bound работы (вычисления, разбор, сжатие, обработка изображений) потоки лишь сменяют друг друга на одном ядре и не дают никакого ускорения.
Многопроцессность полностью обходит GIL. Каждый дочерний процесс — это отдельный интерпретатор Python со своим GIL, поэтому N процессов действительно могут выполнять байт-код Python на N ядрах одновременно.
| Тип нагрузки | Лучший инструмент | Почему |
|---|---|---|
| I/O-bound (запросы, файлы, БД) | threading / asyncio | GIL освобождается во время ожидания; лишние процессы не нужны |
| CPU-bound (математика, разбор, кодирование) | multiprocessing | только отдельные процессы обходят узкое место единого GIL |
Правило: если код занят вычислениями — берите процессы. Если он занят ожиданием — берите потоки или async.