Python 3.7 документация
Я также хотел бы выделить следующую цитату из документации по Pythonthreading
:
Детали реализации CPython: В CPython из-за Глобальной блокировки интерпретатора только один поток может выполнять код Python одновременно (даже если некоторые ориентированные на производительность библиотеки могут преодолеть это ограничение). Если вы хотите, чтобы ваше приложение более эффективно использовало вычислительные ресурсы многоядерных машин, рекомендуется использовать multiprocessing
или concurrent.futures.ProcessPoolExecutor
. Тем не менее, многопоточность по-прежнему является подходящей моделью, если вы хотите запустить несколько задач, связанных с вводом / выводом одновременно.
Эта ссылка на запись Глоссария, дляglobal interpreter lock
которой объясняется, что GIL подразумевает, что многопоточный параллелизм в Python не подходит для задач, связанных с процессором :
Механизм, используемый интерпретатором CPython для гарантии того, что только один поток одновременно выполняет байт-код Python. Это упрощает реализацию CPython, делая объектную модель (включая критические встроенные типы, такие как dict) неявно защищенной от одновременного доступа. Блокировка всего интерпретатора облегчает многопоточность интерпретатора за счет большей части параллелизма, обеспечиваемого многопроцессорными машинами.
Однако некоторые модули расширения, как стандартные, так и сторонние, предназначены для освобождения GIL при выполнении сложных вычислительных задач, таких как сжатие или хеширование. Кроме того, GIL всегда освобождается при выполнении ввода / вывода.
Предпринятые ранее попытки создать интерпретатор с «свободной резьбой» (который блокирует общие данные с более высокой степенью детализации) не увенчались успехом, поскольку в обычном случае с одним процессором пострадала производительность. Считается, что преодоление этой проблемы производительности сделает реализацию намного более сложной и, следовательно, более дорогой в обслуживании.
Эта цитата также подразумевает, что dicts и, следовательно, назначение переменных также являются потокобезопасными, как деталь реализации CPython:
Далее, документы для multiprocessing
пакета объясняют, как он преодолевает GIL, порождая процесс, открывая интерфейс, подобный интерфейсу threading
:
multiprocessing - это пакет, который поддерживает процессы порождения, используя API, похожий на модуль потоков. Многопроцессорный пакет предлагает как локальный, так и удаленный параллелизм, эффективно обходя блокировку глобальной интерпретации, используя подпроцессы вместо потоков. Благодаря этому многопроцессорный модуль позволяет программисту полностью использовать несколько процессоров на данном компьютере. Он работает как на Unix, так и на Windows.
И документыconcurrent.futures.ProcessPoolExecutor
объясняют, что он использует multiprocessing
в качестве бэкэнда:
Класс ProcessPoolExecutor является подклассом Executor, который использует пул процессов для асинхронного выполнения вызовов. ProcessPoolExecutor использует многопроцессорный модуль, который позволяет ему обходить блокировку глобальной интерпретации, но также означает, что только выбираемые объекты могут быть выполнены и возвращены.
который должен быть противопоставлен другому базовому классу, ThreadPoolExecutor
который использует потоки вместо процессов
ThreadPoolExecutor - это подкласс Executor, который использует пул потоков для асинхронного выполнения вызовов.
из чего мы заключаем, что ThreadPoolExecutor
он подходит только для задач, связанных с вводом / выводом, а ProcessPoolExecutor
также может обрабатывать задачи, связанные с процессором.
Следующий вопрос спрашивает, почему GIL существует в первую очередь: почему Global Interpreter Lock?
Процесс против потока экспериментов
В Multiprocessing vs Threading Python я провел экспериментальный анализ процессов против потоков в Python.
Быстрый предварительный просмотр результатов: