Почему Python был написан с помощью GIL?

112

Глобальная блокировка интерпретатора (GIL), по-видимому, часто упоминается в качестве основной причины, по которой многопоточность и тому подобное является сложной задачей в Python - что поднимает вопрос «Почему это было сделано в первую очередь?»

Будучи не программистом, я не имею ни малейшего понятия, почему это может быть - какая логика была в том, чтобы вставить GIL?

фомиты
источник
10
В статье в Википедии говорится, что «GIL может быть существенным барьером для параллелизма - цена, заплаченная за динамичность языка» , и далее говорится, что «Причины использования такой блокировки включают в себя: повышенную скорость однопоточных программ (нет необходимости приобретать или снимать блокировки для всех структур данных по отдельности) и простая интеграция библиотек C, которые обычно не являются поточно-ориентированными. "
Роберт Харви
3
@RobertHarvey, динамизм не имеет к этому никакого отношения. Проблема в мутации.
dan_waterworth
stackoverflow.com/questions/265687/…
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件
1
Не могу не почувствовать, что, как и отсутствие в Java беззнаковых чисел, это было сделано для того, чтобы люди, которые не знают, что они делают, стреляли себе в ноги. К сожалению, тех , кто делает знаю , что они делают получает недостающую язык, который является реальным позором , потому что Python пород многими другими способами
Основные
1
@Basic должен быть какой-то стандартный способ работы с байтовыми массивами в Java (я давно не использовал его) для крипто-математики. У Python (например) нет чисел со знаком, но я бы даже не попытался выполнить побитовые операции с ним, потому что есть лучшие способы.
Ник Т

Ответы:

105

Существует несколько реализаций Python, например, CPython, IronPython, RPython и т. Д.

У некоторых из них есть GIL, у некоторых нет. Например, CPython имеет GIL:

От http://en.wikipedia.org/wiki/Global_Interpreter_Lock

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

Преимущества GIL

  • Увеличена скорость однопоточных программ.
  • Простая интеграция библиотек C, которые обычно не являются поточно-ориентированными.

Почему Python (CPython и другие) использует GIL

В CPython глобальная блокировка интерпретатора, или GIL, является мьютексом, который не позволяет нескольким собственным потокам одновременно выполнять байт-коды Python. Эта блокировка необходима главным образом потому, что управление памятью в CPython не является поточно-ориентированным.

GIL является спорным, поскольку не позволяет многопоточным программам CPython полностью использовать преимущества многопроцессорных систем в определенных ситуациях. Обратите внимание, что потенциально блокирующие или длительные операции, такие как ввод-вывод, обработка изображений и сокращение числа NumPy, происходят вне GIL. Поэтому только в многопоточных программах, которые проводят много времени внутри GIL, интерпретируя байт-код CPython, GIL становится узким местом.

В Python есть GIL, а не мелкозернистая блокировка по нескольким причинам:

  • Это быстрее в однопоточном корпусе.

  • Это быстрее в многопоточном случае для программ, связанных с вводом / выводом.

  • Это быстрее в многопоточном случае для связанных с процессором программ, которые выполняют свою вычислительную работу в библиотеках Си.

  • Это облегчает написание расширений C: переключение потоков Python не произойдет, кроме случаев, когда вы позволите этому произойти (т. Е. Между макросами Py_BEGIN_ALLOW_THREADS и Py_END_ALLOW_THREADS).

  • Это делает упаковку библиотек C проще. Вам не нужно беспокоиться о безопасности потоков. Если библиотека не является поточно-ориентированной, вы просто держите GIL заблокированным во время вызова.

GIL может быть выпущен расширениями C. Стандартная библиотека Python выпускает GIL вокруг каждого блокирующего вызова ввода / вывода. Таким образом, GIL не влияет на производительность серверов, связанных с вводом / выводом. Таким образом, вы можете создавать сетевые серверы в Python, используя процессы (fork), потоки или асинхронный ввод-вывод, и GIL не будет вам мешать.

Числовые библиотеки в C или Fortran могут также вызываться с выпущенным GIL. Пока ваше расширение C ожидает завершения FFT, интерпретатор будет выполнять другие потоки Python. Таким образом, GIL легче и быстрее, чем мелкозернистая блокировка в этом случае. Это составляет основную часть численной работы. Расширение NumPy выпускает GIL, когда это возможно.

Потоки обычно являются плохим способом написания большинства серверных программ. Если нагрузка низкая, разветвление легче. Если нагрузка высока, лучше использовать асинхронный ввод-вывод и программирование на основе событий (например, с использованием Twisted Framework Python). Единственным оправданием использования потоков является отсутствие os.fork в Windows.

GIL является проблемой, если и только если вы выполняете работу с интенсивным использованием процессора на чистом Python. Здесь вы можете получить более чистый дизайн, используя процессы и передачу сообщений (например, mpi4py). В магазине сыра Python также есть модуль обработки, который предоставляет процессам тот же интерфейс, что и потоки (т. Е. Заменяет многопоточность. Нить с обработкой. Процесс).

Потоки могут использоваться для поддержки отзывчивости графического интерфейса независимо от GIL. Если GIL ухудшает вашу производительность (см. Обсуждение выше), вы можете позволить вашему потоку порождать процесс и ждать его завершения.

Md Mahbubur Rahman
источник
52
Похоже, кислый виноград для меня. Python не может выполнять потоки должным образом, поэтому вы выдвигаете причины, по которым потоки не нужны или даже плохие. «Если нагрузка низкая, разветвление легче», серьезно? И GIL «быстрее» для всех этих случаев, только если вы настаиваете на использовании GC с подсчетом ссылок.
Майкл Боргвардт
9
s/RPython/PyPy/g, @MichaelBorgwardt Приводить доводы в пользу GIL - это своего рода вопрос, не так ли? Хотя я бы согласился, что некоторые из содержания этого ответа (а именно обсуждение альтернатив) не имеет смысла. И к лучшему или к худшему, от пересчета теперь почти невозможно избавиться - он глубоко укоренился во всем API и кодовой базе; почти невозможно избавиться от этого, не переписывая половину кода и не нарушая весь внешний код.
10
Не забывайте, multiprocessingбиблиотека - стандартная с 2.6. Его рабочие пулы представляют собой супер гладкую абстракцию для некоторых простых типов параллелизма.
Шон МакSomething
8
@alcalde Только если вы не знаете, что делаете, и / или не хотите, чтобы ваши темы могли работать совместно / общаться. В противном случае, это королевская боль в задней части, особенно учитывая накладные расходы на запуск нового процесса в некоторых ОС. У нас есть серверы с 32 ядрами, поэтому для полного использования их в CPython мне потребуется 32 процесса. Это не «хорошее решение», это хак, чтобы обойти недостатки CPython.
Basic
8
Тот факт, что потоки существуют на платформах, отличных от Windows, должен быть достаточным доказательством того, что разветвление не подходит в любой ситуации.
zneak
42

Прежде всего: Python не имеет GIL. Python - это язык программирования. Язык программирования представляет собой набор абстрактных математических правил и ограничений. В Спецификации языка Python ничего не говорится о том, что должен быть GIL.

Существует много разных реализаций Python. У некоторых есть GIL, у некоторых нет.

Одно простое объяснение наличия GIL заключается в том, что писать параллельный код сложно. Размещая гигантский замок вокруг вашего кода, вы заставляете его всегда работать последовательно. Задача решена!

В частности, в CPython одна важная цель - облегчить расширение интерпретатора с помощью плагинов, написанных на C. Опять же, писать параллельный код сложно, поэтому, гарантируя, что параллелизма не будет, проще будет писать расширения для переводчик. Кроме того, многие из этих расширений являются лишь тонкими обертками вокруг существующих библиотек, которые, возможно, не были написаны с учетом параллелизма.

Йорг Миттаг
источник
6
Это тот же аргумент, что и в Java отсутствие числовых типов без знака - разработчики думают, что все остальные тупее, чем они ...
Basic
1
@Basic - хотите верьте, хотите нет, даже если вы на самом деле не очень глупы, оказывается, что наличие языка, который делает упрощающие предположения, которые означают, что вы не думаете о некоторых вещах, чтобы заставить их работать, все еще полезно вещь. CPython отлично подходит для определенных вещей, включая простые многопоточные приложения (где программа связана с вводом-выводом, а многие из них, и, следовательно, GIL не имеет значения), потому что проектные решения, которые сделали GIL лучшим решением, также облегчают программирование этих приложений. В частности, тот факт, что он поддерживает атомарные операции над коллекциями .
Жюль
@Jules Да, это очень удобно, пока вам не понадобятся эти возможности. «Предпочтительное» решение cpython «просто напишите его на другом языке, таком как c ++», означает, что вы теряете все преимущества Python. Если вы пишете половину своего кода на c ++, тогда зачем начинать с Python? Конечно, для небольших проектов API / клея это быстро и просто, а для ETL это непревзойденно, но не подходит для всего, что требует тяжелой работы. То же самое, что использовать Java для общения с аппаратным обеспечением ... Это почти смешно, когда вам приходится прыгать через обручи.
Базовый
16

Какова цель GIL?

Документация CAPI имеет следующее:

Интерпретатор Python не является полностью потокобезопасным. Для поддержки многопоточных программ Python существует глобальная блокировка, называемая глобальной блокировкой интерпретатора или GIL, которая должна удерживаться текущим потоком, прежде чем он сможет безопасно получить доступ к объектам Python. Без блокировки даже самые простые операции могут вызвать проблемы в многопоточной программе: например, когда два потока одновременно увеличивают счетчик ссылок одного и того же объекта, счетчик ссылок может увеличиваться только один раз, а не дважды.

Другими словами, GIL предотвращает коррупцию государства. Программы Python никогда не должны вызывать ошибки сегментации, потому что разрешены только безопасные операции с памятью. GIL распространяет эту гарантию на многопоточные программы.

Какие есть альтернативы?

Если целью GIL является защита государства от коррупции, то очевидной альтернативой является блокировка гораздо более тонкого зерна; возможно на уровне объекта. Проблема заключается в том, что, хотя было продемонстрировано, что оно повышает производительность многопоточных программ, в результате возникают дополнительные издержки, и в результате страдают однопоточные программы.

dan_waterworth
источник
2
Было бы здорово позволить пользователю запустить программу с опцией интерпретатора, заменяющей gil для мелкозернистой блокировки, и каким-то образом узнать - только для чтения - был ли текущий процесс вызван с или без gil.
Луис Масуэлли
Несмотря на GIL, мне удалось вызвать ошибку сегментации в многопоточной программе из-за небрежного использования модуля pyodbc. Таким образом, «никогда не должно вызывать ошибки сегментации» - заблуждение.
Muposat