Какова именно функция глобальной блокировки интерпретатора Python? Используют ли другие языки, скомпилированные в байт-код, аналогичный механизм?
Какова именно функция глобальной блокировки интерпретатора Python? Используют ли другие языки, скомпилированные в байт-код, аналогичный механизм?
Ответы:
В общем, для решения любой проблемы с безопасностью потоков вам необходимо защитить свои внутренние структуры данных с помощью блокировок. Это можно сделать с различными уровнями детализации.
Вы можете использовать детализированную блокировку, когда каждая отдельная структура имеет свою собственную блокировку.
Вы можете использовать грубую блокировку, когда одна блокировка защищает все (подход GIL).
У каждого метода есть свои плюсы и минусы. Детальная блокировка обеспечивает больший параллелизм - два потока могут выполняться параллельно, когда они не разделяют никаких ресурсов. Однако существуют гораздо большие административные издержки. Для каждой строки кода может потребоваться установить и снять несколько блокировок.
При крупнозернистом подходе все наоборот. Два потока не могут выполняться одновременно, но отдельный поток будет работать быстрее, потому что он не выполняет так много учетных записей. В конечном итоге все сводится к компромиссу между однопоточной скоростью и параллелизмом.
Было предпринято несколько попыток удалить GIL в python, но дополнительные накладные расходы для однопоточных машин обычно были слишком большими. В некоторых случаях даже на многопроцессорных машинах может происходить медленнее из-за конфликта блокировок.
Используют ли другие языки, скомпилированные в байт-код, аналогичный механизм?
Он варьируется, и, вероятно, его не следует рассматривать как свойство языка, а скорее как свойство реализации. Например, существуют реализации Python, такие как Jython и IronPython, которые используют поточный подход своей базовой виртуальной машины, а не подход GIL. Кроме того, следующая версия Ruby, похоже, будет продвигаться к введению GIL.
Следующее взято из официального Справочного руководства Python / C API :
Интерпретатор Python не является полностью потокобезопасным. Для поддержки многопоточных программ Python существует глобальная блокировка, которая должна удерживаться текущим потоком, прежде чем он сможет безопасно обращаться к объектам Python. Без блокировки даже самые простые операции могут вызвать проблемы в многопоточной программе: например, когда два потока одновременно увеличивают счетчик ссылок одного и того же объекта, счетчик ссылок может увеличиваться только один раз, а не дважды.
Следовательно, существует правило, согласно которому только поток, получивший глобальную блокировку интерпретатора, может работать с объектами Python или вызывать функции API Python / C. Для поддержки многопоточных программ Python интерпретатор регулярно снимает и повторно устанавливает блокировку - по умолчанию каждые 100 инструкций байт-кода (это можно изменить с помощью sys.setcheckinterval ()). Блокировка также снимается и повторно устанавливается вокруг потенциально блокирующих операций ввода-вывода, таких как чтение или запись файла, так что другие потоки могут работать, пока поток, запрашивающий ввод-вывод, ожидает завершения операции ввода-вывода.
Я думаю, что это довольно хорошо резюмирует проблему.
Глобальная блокировка интерпретатора - это большая блокировка типа мьютекса, которая защищает счетчики ссылок от перехвата. Если вы пишете чистый код Python, все это происходит за кулисами, но если вы встраиваете Python в C, вам, возможно, придется явно снять / снять блокировку.
Этот механизм не связан с компиляцией Python в байт-код. Для Java это не нужно. Фактически, это даже не нужно для Jython (python, скомпилированный в jvm).
см. также этот вопрос
Python, как и Perl 5, изначально не разрабатывался как потокобезопасный. Потоки были наложены постфактум, поэтому глобальная блокировка интерпретатора используется для поддержания взаимного исключения, когда только один поток выполняет код в данный момент времени в недрах интерпретатора.
Отдельные потоки Python совместно выполняют многозадачность самим интерпретатором, время от времени циклически переключая блокировку.
Самостоятельно захватить блокировку необходимо, когда вы разговариваете с Python из C, когда другие потоки Python активны, чтобы «выбрать» этот протокол и убедиться, что за вашей спиной ничего небезопасного не происходит.
Другие системы, унаследованные от однопоточных, которые позже превратились в многопоточные системы, часто имеют какой-либо механизм такого рода. Например, ядро Linux имеет «Big Kernel Lock» с первых дней SMP. Постепенно по мере того, как производительность многопоточности становится проблемой, появляется тенденция пытаться разбивать такие блокировки на более мелкие части или заменять их алгоритмами без блокировок и структурами данных, где это возможно, для максимизации пропускной способности.
reiserfs
- единственная реальная причина, по которой я вообще знаю об этом).
Что касается вашего второго вопроса, не все языки сценариев используют это, но это только делает их менее мощными. Например, потоки в Ruby зеленые и неродные.
В Python потоки являются собственными, и GIL только предотвращает их запуск на разных ядрах.
В Perl потоки еще хуже. Они просто копируют весь интерпретатор и далеко не так удобны, как в Python.
Может быть, эта статья BDFL поможет.