Чому Python був написаний з GIL?


112

Глобальний замок інтерпретатора (GIL), здається, часто називають основною причиною того, чому нарізка ниток тощо - це хитрість у Python - що викликає питання "Чому це було зроблено в першу чергу?"

Будучи не програмістом, я не маю поняття, чому це могло бути - якою була логіка введення GIL?


10
У статті Вікіпедії зазначається, що "GIL може бути суттєвим бар'єром для паралелізму - ціною, яка сплачується за динамізм мови" , і далі йдеться про те, що "Причини використання такого блокування включають: збільшення швидкості однопотокових програм (немає необхідності купувати або випускати блокування для всіх структур даних окремо), а також легка інтеграція бібліотек C, яка зазвичай не є безпечною для потоків ".
Роберт Харві

3
@RobertHarvey, динамізм ні до чого. Проблема - мутація.
dan_waterworth


1
Не можу не відчути, що, як відсутність Яви непідписаних числових цифр, вона мала на меті запобігти людям, які не знають, що вони роблять, стріляючи в ногу. На жаль, тих , хто робить знаю , що вони роблять отримує відсутню мову, який є реальним ганьбою , тому що 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 не заважатиме.

Числові бібліотеки в С або Фортран можна аналогічно назвати із звільненим GIL. Поки ваше розширення C очікує завершення FFT, інтерпретатор виконує інші потоки Python. Таким чином, GIL є простішим та швидшим, ніж дрібнозернисте блокування і в цьому випадку. Це складає основну частину чисельної роботи. Розширення NumPy випускає GIL, коли це можливо.

Нитки зазвичай є поганим способом написання більшості серверних програм. Якщо навантаження низька, розгортання легше. Якщо навантаження велика, краще асинхронне введення / виведення та програмування на основі подій (наприклад, використання Twisted Framework Python). Єдиним приводом для використання потоків є відсутність os.fork у Windows.

GIL - це проблема, якщо і лише тоді, коли ви робите інтенсивну роботу процесора в чистому Python. Тут ви можете отримати більш чіткий дизайн за допомогою процесів і передачі повідомлень (наприклад, mpi4py). Також у сирному цеху Python є модуль "обробки", який надає процесам той самий інтерфейс, що і потоки (тобто замінює нарізання. Thread на обработку.Process).

Нитки можна використовувати для підтримки чутливості графічного інтерфейсу незалежно від GIL. Якщо GIL погіршує вашу ефективність (див. Обговорення вище), ви можете дозволити вашому потоку породити процес і чекати, коли він закінчиться.


52
Мені звучить як кислий виноград. Python не може робити нитки належним чином, тому ви виправляєте причини, через які нитки непотрібні або навіть погані. "Якщо навантаження низька, розпалювання легше", серйозно? І GIL "швидший" для всіх тих випадків, лише якщо ви наполягаєте на використанні GC, що рахує референт.
Майкл Боргвардт

9
s/RPython/PyPy/g. @MichaelBorgwardt Надання причин про GIL - це певна суть питання, чи не так? Хоча я погоджуюся, що частина змісту цієї відповіді (а саме обговорення альтернатив) не відповідає суті. І в кращу сторону, або в гіршу сторону від повернення рахунків тепер практично неможливо позбутися - вона глибоко вкорінена у всій базі API та коду; позбутися цього практично неможливо, не переписавши половину коду і не порушивши весь зовнішній код.

10
Не забувайте multiprocessingбібліотеку - стандартну з 2.6. Це пули робітників - це надзвичайно гладка абстракція для простих видів паралелізму.
Sean McSomething

8
@alcalde Тільки якщо ви не знаєте, чим займаєтесь та / або не хочете, щоб ваші теми могли працювати спільно / спілкуватися. В іншому випадку це королівський біль ззаду, особливо враховуючи накладні витрати на запуск нового процесу на деяких ОС. У нас є сервери з 32 ядрами, тому для повного використання їх у CPython мені знадобиться 32 процеси. Це не "гарне рішення", це зламати недоліки CPython.
Основні

8
Те, що потоки існують на інших платформах, крім Windows, повинно бути достатньою доказою того, що розгортання не є адекватним у будь-якій ситуації.
zneak

42

По-перше: Python не має GIL. Python - мова програмування. Мова програмування - це набір абстрактних математичних правил та обмежень. У специфікації мови Python немає нічого, що говорить про те, що повинен бути GIL.

Існує багато різних реалізацій Python. Деякі мають GIL, деякі ні.

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

Зокрема, у CPython важливою метою є полегшення розширення інтерпретатора на плагіни, написані на C. Знову ж таки, написання одночасного коду є важким, тому гарантуючи, що не буде одночасності, це полегшує запис розширень для перекладач. Крім того, багато з цих розширень є лише тонкими обгортками навколо існуючих бібліотек, які, можливо, не були написані з однозначністю.


6
Це той самий аргумент, як відсутність Яви непідписаних числових типів - розробники вважають, що всі інші тупіші, ніж вони ...
Basic

1
@Basic - віриш чи ні, навіть коли ти насправді не дуже глум, виявляється, що мова, яка спрощує припущення, що означає, що ти не думаєш про певні речі, щоб змусити їх працювати, все-таки корисно. річ. CPython чудово підходить для певних речей, включаючи прості багатопотокові програми (де програма пов'язана з IO, яких багато, і тому GIL не має значення), оскільки проектні рішення, які зробили GIL найкращим рішенням, також спрощують програмування цих додатків , особливо той факт, що він підтримує атомні операції над колекціями .
Жуль

@Jules Так, це дуже зручно до тих пір, поки вам не потрібні ці можливості. "Краще" рішення cpython "просто запишіть його на іншій мові, як, наприклад, c ++", то означає, що ви втрачаєте будь-яку перевагу пітона. Якщо ви пишете половину коду на мові c ++, то навіщо починати з Python? Звичайно, для невеликих проектів API / клею це швидко і просто, а для ETL - це другий, але це не підходить для нічого, що вимагає важкого підйому. Те саме, що використовувати Java для розмови з обладнанням ... Це майже комічні обручі, через які ви повинні перестрибнути.
Основний

16

Яке призначення GIL?

Документація CAPI має таке слово з цього приводу:

Інтерпретатор Python не є повністю безпечним для потоків. Для підтримки багатопотокових програм Python існує глобальний замок, який називається глобальним блоком інтерпретатора або GIL, який повинен утримуватися поточним потоком, перш ніж він зможе безпечно отримати доступ до об’єктів Python. Без блокування навіть найпростіші операції можуть спричинити проблеми в багатопотоковій програмі: наприклад, коли два потоки одночасно збільшують кількість відліку одного і того ж об'єкта, то кількість посилань може збільшитися лише один раз, а не двічі.

Іншими словами, GIL запобігає корупції держави. Програми Python ніколи не повинні створювати помилки сегментації, оскільки дозволені лише безпечні операції з пам'яттю. GIL поширює цю гарантію на багатопотокові програми.

Які альтернативи?

Якщо метою ГІЛ є захист держави від корупції, то однією очевидною альтернативою є замок із значно кращим зерном; можливо, на рівні об'єкта. Проблема в цьому полягає в тому, що, хоча було продемонстровано підвищення продуктивності багатопотокових програм, внаслідок цього страждають більше накладних та однопотокових програм.


2
Було б чудово дозволити користувачеві запускати програму з варіантом інтерпретації, що замінює gil на дрібнозернистий замок, і якось дізнатися - начитаний спосіб - чи піднімався поточний процес з gil або без нього.
Луїс Масуеллі

Незважаючи на GIL, мені вдалося створити помилку сегментації в багатопотоковій програмі через необережне використання модуля pyodbc. Таким чином, "ніколи не повинно бути помилкою сегментації" є помилкою.
Muposat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.