Что такое глобальная блокировка интерпретатора и почему это проблема?
Было много шума вокруг удаления GIL из Python, и я хотел бы понять, почему это так важно. Я никогда не писал ни компилятор, ни интерпретатор, так что не будьте скромны с деталями, мне, вероятно, понадобится их понять.
python
python-internals
gil
е-удовлетворяться
источник
источник
Ответы:
GIL Python предназначен для сериализации доступа к внутренним компонентам интерпретатора из разных потоков. В многоядерных системах это означает, что несколько потоков не могут эффективно использовать несколько ядер. (Если бы GIL не привел к этой проблеме, большинство людей не заботились бы о GIL - он поднимается только как проблема из-за растущей распространенности многоядерных систем.) Если вы хотите понять это подробно, Вы можете просмотреть это видео или посмотреть этот набор слайдов . Это может быть слишком много информации, но тогда вы спросили детали :-)
Обратите внимание, что GIL Python на самом деле является проблемой только для CPython, эталонной реализации. У Jython и IronPython нет GIL. Как разработчик Python, вы обычно не сталкиваетесь с GIL, если не пишете расширение на C. Авторы расширений C должны освобождать GIL, когда их расширения блокируют ввод / вывод, чтобы другие потоки в процессе Python могли запускаться.
источник
regex
,lxml
,numpy
модули. Cython позволяет выпускать GIL в пользовательском коде, например,b2a_bin(data)
Предположим , у вас есть несколько потоков , которые не очень трогают данные друг друга. Они должны выполняться как можно более независимо. Если у вас есть «глобальная блокировка», которую вы должны получить, чтобы (скажем) вызвать функцию, это может в конечном итоге стать узким местом. Вы можете не получить много пользы от множества потоков.
Чтобы представить это в реальной аналогии: представьте, что 100 разработчиков работают в компании, имеющей только одну кофейную кружку. Большинство разработчиков будут тратить время на ожидание кофе вместо кодирования.
Ничто из этого не относится к Python - я не знаю деталей того, для чего Python нужен GIL. Тем не менее, надеюсь, это даст вам лучшее представление об общей концепции.
источник
Давайте сначала разберемся, что обеспечивает Python GIL:
Любая операция / инструкция выполняется в интерпретаторе. GIL гарантирует, что переводчик удерживается одним потоком в определенный момент времени . И ваша программа на Python с несколькими потоками работает в одном интерпретаторе. В любой конкретный момент времени этот переводчик удерживается одним потоком. Это означает, что в любой момент времени работает только тот поток, который содержит интерпретатор .
Теперь, почему это проблема:
Ваша машина может иметь несколько ядер / процессоров. И несколько ядер позволяют выполнять несколько потоков одновременно, т.е. несколько потоков могут выполняться в любой конкретный момент времени. , Но поскольку интерпретатор удерживается одним потоком, другие потоки ничего не делают, даже если у них есть доступ к ядру. Таким образом, вы не получаете никаких преимуществ, предоставляемых несколькими ядрами, потому что в любой момент используется только одно ядро, то есть ядро, используемое потоком, который в настоящее время содержит интерпретатор. Таким образом, ваша программа будет выполняться так же долго, как если бы это была однопоточная программа.
Однако потенциально блокирующие или длительные операции, такие как ввод-вывод, обработка изображений и сокращение числа NumPy, происходят вне GIL. Взято отсюда . Таким образом, для таких операций многопоточная операция все равно будет быстрее однопоточной, несмотря на наличие GIL. Таким образом, GIL не всегда является узким местом.
Изменить: GIL является деталью реализации CPython. IronPython и Jython не имеют GIL, поэтому в них должна быть по-настоящему многопоточная программа, хотя я никогда не использовал PyPy и Jython и не уверен в этом.
источник
Python не допускает многопоточность в прямом смысле этого слова. Он имеет многопоточный пакет, но если вы хотите многопоточность для ускорения вашего кода, то, как правило, его не рекомендуется использовать. Python имеет конструкцию, называемую Global Interpreter Lock (GIL).
https://www.youtube.com/watch?v=ph374fJqFPE
GIL гарантирует, что только один из ваших «потоков» может выполняться одновременно. Поток получает GIL, выполняет небольшую работу, а затем передает GIL следующему потоку. Это происходит очень быстро, поэтому человеческому глазу может показаться, что ваши потоки выполняются параллельно, но на самом деле они просто по очереди используют одно и то же ядро ЦП. Вся эта передача GIL увеличивает накладные расходы на выполнение. Это означает, что если вы хотите, чтобы ваш код работал быстрее, то использование потокового пакета часто не является хорошей идеей.
Есть причины использовать пакет потоков Python. Если вы хотите запускать некоторые вещи одновременно, а эффективность не имеет значения, тогда это совершенно нормально и удобно. Или, если вы запускаете код, которому нужно что-то ждать (например, какой-нибудь ввод-вывод), тогда это может иметь большой смысл. Но библиотека потоков не позволит вам использовать дополнительные ядра процессора.
Многопоточность может быть передана на аутсорсинг операционной системе (посредством многопроцессорной обработки), некоторому внешнему приложению, которое вызывает ваш код Python (например, Spark или Hadoop), или некоторому коду, который вызывает ваш код Python (например, у вас может быть ваш Python код вызывает функцию C, которая делает дорогие многопоточные вещи).
источник
Всякий раз, когда два потока имеют доступ к одной и той же переменной, у вас возникает проблема. Например, в C ++ способ избежать этой проблемы состоит в том, чтобы определить некоторую блокировку мьютекса, чтобы два потока, скажем, не могли одновременно вводить установщик объекта.
Многопоточность возможна в Python, но два потока не могут быть выполнены одновременно с более высокой степенью детализации, чем одна инструкция Python. Работающий поток получает глобальную блокировку под названием GIL.
Это означает, что если вы начнете писать многопоточный код, чтобы использовать преимущества многоядерного процессора, ваша производительность не улучшится. Обычный обходной путь состоит в многопроцессорности.
Обратите внимание, что возможно выпустить GIL, если вы находитесь внутри метода, который вы написали, например, в Си.
Использование GIL присуще не Python, а некоторым его интерпретаторам, включая самый распространенный CPython. (отредактировано, см. комментарий)
Проблема GIL все еще актуальна в Python 3000.
источник
Python 3.7 документация
Я также хотел бы выделить следующую цитату из документации по Python
threading
:Эта ссылка на запись Глоссария, для
global interpreter lock
которой объясняется, что GIL подразумевает, что многопоточный параллелизм в Python не подходит для задач, связанных с процессором :Эта цитата также подразумевает, что dicts и, следовательно, назначение переменных также являются потокобезопасными, как деталь реализации CPython:
Далее, документы для
multiprocessing
пакета объясняют, как он преодолевает GIL, порождая процесс, открывая интерфейс, подобный интерфейсуthreading
:И документы
concurrent.futures.ProcessPoolExecutor
объясняют, что он используетmultiprocessing
в качестве бэкэнда:который должен быть противопоставлен другому базовому классу,
ThreadPoolExecutor
который использует потоки вместо процессовиз чего мы заключаем, что
ThreadPoolExecutor
он подходит только для задач, связанных с вводом / выводом, аProcessPoolExecutor
также может обрабатывать задачи, связанные с процессором.Следующий вопрос спрашивает, почему GIL существует в первую очередь: почему Global Interpreter Lock?
Процесс против потока экспериментов
В Multiprocessing vs Threading Python я провел экспериментальный анализ процессов против потоков в Python.
Быстрый предварительный просмотр результатов:
источник
Почему Python (CPython и другие) использует GIL
От http://wiki.python.org/moin/GlobalInterpreterLock
В CPython глобальная блокировка интерпретатора, или GIL, является мьютексом, который не позволяет нескольким собственным потокам одновременно выполнять байт-коды Python. Эта блокировка необходима главным образом потому, что управление памятью в CPython не является поточно-ориентированным.
Как удалить это из Python?
Как и Lua, возможно, Python может запустить несколько ВМ, но Python этого не делает, я думаю, должны быть и другие причины.
В Numpy или какой-либо другой расширенной библиотеке Python иногда выпуск GIL для других потоков может повысить эффективность всей программы.
источник
Я хочу поделиться примером из книги многопоточности для визуальных эффектов. Так вот классическая ситуация блокировки
Теперь рассмотрим события в последовательности, приводящие к тупику.
источник