Яка саме функція блокування інтерпретатора Python? Чи використовують інші мови, скомпільовані в байт-код, подібний механізм?
Яка саме функція блокування інтерпретатора Python? Чи використовують інші мови, скомпільовані в байт-код, подібний механізм?
Відповіді:
Загалом, для будь-якої проблеми безпеки потоку вам потрібно буде захистити свої внутрішні структури даних замками. Це можна зробити з різним рівнем деталізації.
Ви можете використовувати дрібнозернистий замок, де кожна окрема конструкція має власний замок.
Ви можете використовувати грубозернистий замок, де один замок захищає все (підхід GIL).
У кожного методу є різні плюси і мінуси. Дрібнозернисте блокування забезпечує більший паралелізм - два потоки можуть виконуватися паралельно, коли вони не мають спільних ресурсів. Однак є значно більші адміністративні накладні витрати. Для кожного рядка коду вам може знадобитися придбати та звільнити кілька блокувань.
Грубозернистий підхід протилежний. Два потоки не можуть працювати одночасно, але окремий потік буде працювати швидше, оскільки він не робить так багато бухгалтерії. Зрештою, це зводиться до компромісу між однопоточною швидкістю та паралелізмом.
Було кілька спроб видалити GIL у python, але додаткові накладні витрати для однопоточних машин, як правило, були занадто великими. Деякі випадки можуть бути повільнішими навіть на багатопроцесорних машинах через суперечку про блокування.
Чи використовують інші мови, скомпільовані в байт-код, подібний механізм?
Вона варіюється, і, ймовірно, її не слід вважати властивістю мови настільки, як властивістю реалізації. Наприклад, існують реалізації Python, такі як Jython та IronPython, які використовують підхід з потоками своєї базової ВМ, а не підхід GIL. Крім того, наступна версія Ruby, схоже, рухається до запровадження GIL.
Далі йдеться з офіційного довідкового посібника API Python / C :
Інтерпретатор Python не є повністю безпечним для потоків. Для підтримки багатопотокових програм Python існує глобальний замок, який повинен утримуватися поточним потоком, перш ніж він зможе безпечно отримати доступ до об’єктів Python. Без блокування навіть найпростіші операції можуть викликати проблеми в багатопотоковій програмі: наприклад, коли два потоки одночасно збільшують кількість посилань одного і того ж об'єкта, кількість посилань може в підсумку збільшитися лише один раз, а не двічі.
Отже, існує правило, що лише потік, який отримав глобальну блокування інтерпретатора, може працювати з об'єктами Python або викликати функції API Python / C. Для підтримки багатопотокових програм Python інтерпретатор регулярно випускає і знову отримує блокування - за замовчуванням кожні 100 інструкцій байт-коду (це можна змінити за допомогою sys.setcheckinterval ()). Блокування також вивільняється та повторно отримується навколо потенційно блокуючих операцій вводу-виводу, таких як читання або запис файлу, так що інші потоки можуть працювати, поки потік, що запитує введення-виведення, чекає завершення операції вводу-виводу.
Думаю, це досить добре підсумовує проблему.
Глобальний інтерпретатор - це великий замок типу mutex, який захищає лічильники посилань від шлангу. Якщо ви пишете чистий код python, все це відбувається за лаштунками, але якщо ви вбудовуєте Python в C, можливо, вам доведеться явно взяти / звільнити блокування.
Цей механізм не пов'язаний з Python, який компілюється в байт-код. Це не потрібно для Java. Насправді це навіть не потрібно для Jython (python скомпільований у jvm).
див. також це питання
Python, як і perl 5, не був розроблений з нуля, щоб бути безпечним для потоків. Потоки були прищеплені після факту, тому глобальний блокувальник інтерпретатора використовується для підтримки взаємного виключення туди, де лише один потік виконує код у певний момент часу в надрах інтерпретатора.
Індивідуальні потоки Python багатозадачно виконуються інтерпретатором, періодично перемикаючи блокування.
Самостійно захопити замок потрібно, коли ви розмовляєте з Python з C, коли інші потоки Python активні, щоб «увімкнути» цей протокол і переконатися, що за вашою спиною не відбувається нічого небезпечного.
Інші системи, які мають однопоточну спадщину, яка пізніше переросла у багатопотокові системи, часто мають певний механізм подібного роду. Наприклад, ядро Linux має "Блокування великого ядра" з перших днів SMP. Поступово, з часом, як продуктивність багатопоточності стає проблемою, існує тенденція намагатися розбити подібні замки на менші частини або замінити їх безблокувальними алгоритмами та структурами даних, де це можливо, щоб максимізувати пропускну здатність.
reiserfs
- єдина справжня причина, що я про це взагалі знаю).
Що стосується Вашого другого питання, не всі мови сценаріїв використовують це, але це лише робить їх менш потужними. Наприклад, нитки в Ruby зелені і не є рідними.
У Python потоки є рідними, і GIL лише заважає їм працювати на різних ядрах.
У Perl нитки ще гірші. Вони просто копіюють весь інтерпретатор і далеко не настільки корисні, як у Python.
Можливо, ця стаття BDFL допоможе.