Почему Глобальная Блокировка Интерпретатора?

Какова именно функция Python Global Interpreter Lock? Используют ли другие языки, скомпилированные для байт-кода, аналогичный механизм?

6 ответов

В общем, для любой проблемы безопасности потоков вам нужно будет защитить внутренние структуры данных с помощью блокировок. Это может быть сделано с различными уровнями детализации.

  • Вы можете использовать мелкозернистую блокировку, где каждая отдельная структура имеет свою собственную блокировку.

  • Вы можете использовать грубую блокировку, когда одна блокировка защищает все (подход GIL).

Есть разные плюсы и минусы каждого метода. Мелкозернистая блокировка обеспечивает больший параллелизм - два потока могут выполняться параллельно, если они не совместно используют ресурсы. Однако административные издержки значительно выше. Для каждой строки кода вам может потребоваться получить и снять несколько блокировок.

Грубый подход противоположен. Два потока не могут работать одновременно, но отдельный поток будет работать быстрее, потому что он не делает так много бухгалтерии. В конечном итоге все сводится к компромиссу между однопоточной скоростью и параллелизмом.

Было несколько попыток удалить GIL в python, но дополнительные издержки для однопоточных машин, как правило, были слишком большими. Некоторые случаи могут быть медленнее даже на многопроцессорных компьютерах из-за конфликта блокировок.

Используют ли другие языки, скомпилированные для байт-кода, аналогичный механизм?

Он варьируется, и, вероятно, его не следует рассматривать как свойство языка, а как свойство реализации. Например, есть реализации Python, такие как Jython и IronPython, которые используют многопоточный подход своей базовой виртуальной машины, а не подход GIL. Кроме того, следующая версия Ruby, похоже, движется к внедрению GIL.

Ниже приводится официальное справочное руководство по API Python/C:

Интерпретатор 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. Постепенно со временем, когда производительность многопоточности становится проблемой, возникает тенденция разбивать эти виды блокировок на более мелкие части или заменять их алгоритмами без блокировки и структурами данных, где это возможно, для максимизации пропускной способности.

Что касается вашего второго вопроса, не все языки сценариев используют это, но это только делает их менее мощными. Например, потоки в Ruby являются зелеными, а не нативными.

В Python потоки являются родными, и GIL только запрещает им работать на разных ядрах.

В Perl темы еще хуже. Они просто копируют весь интерпретатор и далеко не так удобны, как в Python.

Может быть, эта статья BDFL поможет.

Другие вопросы по тегам