No-GIL CPython डेवलपमेंट की प्रगति
(lwn.net)- Python steering council ने कई releases में GIL को optional बनाने वाले PEP 703 को मंजूरी देने का इरादा जताया है, हालांकि अंतिम शर्तें अभी तय होनी बाकी हैं
- CPython 3.13 का
--disable-gilbuild experimental रूप में तैयार किया जा रहा है, और stable ABI तथा extension module wheel compatibility सबसे बड़े technical मुद्दों के रूप में उभर रहे हैं - मौजूदा
abi3wheels शायद no-GIL CPython 3.13 पर सीधे compatible न हों, इसलिएabi4लाने, limited C API में बदलाव, और reference counting macros को function calls में बदलने पर चर्चा हो रही है - यह चिंता भी है कि
pipGIL build और no-GIL build के लिए गलत wheel चुन सकता है, और चुपचाप गलत install होना साधारण install failure से ज्यादा खतरनाक है - no-GIL build के नाम के लिए
nogilकी जगह free-threading प्रस्तावित किया गया है, लेकिन executable name, shebang, parallel installation, और distribution packaging जैसे मुद्दे भी साथ में सुलझाने होंगे
PEP 703 और no-GIL CPython की मौजूदा स्थिति
- Python steering council ने जुलाई के आखिर में PEP 703 को मंजूरी देने का इरादा जताया था। इस PEP में CPython में global interpreter lock (GIL) को optional बनाने का प्रस्ताव है
- मंजूरी की बारीक शर्तें अभी अंतिम रूप में तय नहीं हुई हैं, लेकिन implementation पर चर्चा और ecosystem की तैयारी पहले से चल रही है
- लंबी अवधि में बिना GIL वाले एक single CPython version की दिशा सोची जा रही है, लेकिन फिलहाल
--disable-giloption से build किए गए interpreter में no-GIL behavior को test किया जा रहा है - CPython 3.13 अक्टूबर 2024 में अपेक्षित है, और इस version का no-GIL build experimental होगा
stable ABI और extension module compatibility
- Sam Gross ने Python discussion forum में PEP 703 और CPython stable ABI के आपसी संबंध पर चर्चा की
- stable ABI का मकसद यह है कि extension modules कई CPython versions में एक ही binary wheel के साथ चल सकें, ताकि हर नए CPython release पर उन्हें फिर से rebuild न करना पड़े
- stable ABI के लिए built extensions, CPython 3.13 no-GIL build पर सीधे काम न करें, ऐसा संभव है
- इसे हल करने के लिए limited C API में कुछ additions और changes प्रस्तावित हैं
- जो extensions केवल limited C API का उपयोग करते हैं, वे stable ABI वाला binary बना सकते हैं
- प्रस्तावित बदलावों में object reference count बढ़ाने-घटाने वाले कुछ macros को function calls में बदलने की पुरानी योजना भी शामिल है
- लक्ष्य यह है कि ऐसे extension binaries संभव हों जो GIL build और no-GIL build दोनों पर चल सकें
abi3, abi4, और wheel selection की समस्या
- Victor Stinner का मानना है कि no-GIL experiment के सफल होने के लिए ऐसा सरल समाधान चाहिए जो दोनों interpreter types पर चलने वाले extensions के लिए काम करे
- CPython 3.12 या उससे नीचे stable ABI के लिए built extensions, 3.13 के बाद के no-GIL builds के साथ compatible नहीं होंगे, इसलिए नए ABI version abi4 का विचार सामने आया है
- मौजूदा stable ABI
abi3है - ABI number का CPython major version number से अनिवार्य रूप से जुड़ा होना जरूरी नहीं है
- मौजूदा stable ABI
- Gross का मानना है कि no-GIL support चाहने वाले extensions दो binary wheels बनाने का बोझ कुछ हद तक स्वीकार कर सकते हैं
- उन्हें इस बात की ज्यादा चिंता है कि no-GIL project, C API और stable ABI सुधारों से जरूरत से ज्यादा बंध न जाए
- Alex Gaynor के पास भी कई
abi3wheel packages हैं, लेकिन उनके अनुसार एक बार दो wheels बनाना बहुत बड़ा बोझ नहीं है- हालांकि मौजूदा और भविष्य के
pipका सही wheel चुनना अहम रहेगा
- हालांकि मौजूदा और भविष्य के
- Brett Cannon का मानना है कि मौजूदा
piplogic दोनों versions में फर्क नहीं कर सकता, इसलिएabi4जैसे बदलाव के बिना मौजूदा और पुरानेpipसही तरह काम नहीं करेंगे
pip के चुपचाप गलत काम करने की चिंता
- Gross का मानना है कि CPython 3.13 के experimental
--disable-gilbuild में पुरानेpipsupport की बहुत ज्यादा चिंता करने की जरूरत नहीं है- उनका तर्क है कि नए Python versions पर पुराने
pipका टूटना आम बात है - उदाहरण के तौर पर उन्होंने बताया कि
pip==23.1.1या उससे नीचे के versions, CPython 3.13 परpkgutil.ImpImporterके न होने से टूट जाते हैं
- उनका तर्क है कि नए Python versions पर पुराने
pipmaintainer Paul Moore का कहना है कि स्पष्ट रूप से टूटना और चुपचाप गलत package install कर देना दो अलग समस्याएं हैं- कुछ users पुराने
pipका इस्तेमाल करते हैं - स्पष्ट failure और silent error का user impact अलग होता है
- कुछ users पुराने
- Moore को चिंता है कि अगर no-GIL या free-threaded build आजमाने वाले users को ABI compatibility issues debug करने पड़ें, तो उनका उत्साह कम हो सकता है
- Gaynor का भी मानना है कि अगर प्रभावित packages में
pipचुपचाप गलत व्यवहार करे, तो issues की बाढ़ आ सकती है
parallel installation और executable names
- Barry Warsaw ने पूछा कि क्या एक ही system पर GIL build और no-GIL build को साथ install करने की योजना है
- Gross ने जवाब दिया कि यह स्थिति अलग-अलग Python versions install करने जैसी ही है
- Cannon का मानना है कि एक “fat” wheel में दोनों binaries रखना भी संभव है
- हालांकि wheel के अंदर binaries के नाम अलग होने चाहिए
- executable names पर चर्चा फिर एक अलग thread में चली गई
- Paul Moore का मानना है कि users को no-GIL mode आसानी से test करने और GIL/no-GIL में से किसी एक को आसानी से चुनने की सुविधा होनी चाहिए
- अगर Windows, macOS, Linux आदि पर यह प्रक्रिया कठिन हुई, तो no-GIL project पर नकारात्मक असर पड़ सकता है
- users के लिए इसे आसान बनाना जरूरी है, तभी no-GIL builds की demand बनेगी और package maintainers पर no-GIL compatible wheels देने का दबाव भी आएगा
nogil बनाम free-threading नाम को लेकर बहस
- Barry Scott का मानना है कि shebang line में किस interpreter को बुलाना है यह दिखाना जरूरी होगा, इसलिए executable name महत्वपूर्ण है
- उदाहरण के तौर पर उन्होंने
python-nogil3,python-nogil3.13जैसे नाम सुझाए
- उदाहरण के तौर पर उन्होंने
- Gregory P. Smith ने अपनी निजी राय दी कि CPython 3.13 का no-GIL build experimental feature है, इसलिए distributions को इसे default
$PATHमें नहीं रखना चाहिए- उनका यह भी मानना है कि बहुत लंबे executable names का shebang में लंबे समय तक बने रहना उचित नहीं होगा
- उन्होंने install naming का अंतिम फैसला 3.14 या उसके बाद तक टालने का सुझाव दिया
- Fedora developer Petr Viktorin ने कहा कि distributions संभवतः users के experimentation के लिए no-GIL interpreter को package करना चाहेंगी
- Moore का मानना है कि वे
#!/usr/bin/env python3.13-nogilजैसे रूप में free-threaded build को specify कर सकें- इसका उद्देश्य लंबा और कम intuitive path hardcode करने से बचना है
- Steve Dower द्वारा शुरू की गई Windows installer thread में Smith ने बताया कि steering council
nogilनाम से बचना चाहती है- वजह यह है कि यह अधिकतर non-core developers तक साफ तौर पर संदेश नहीं देता, GIL क्या है यह जानना जरूरी मान लेता है, और negative expression का उपयोग करता है
- विकल्प के रूप में free-threading शब्द प्रस्तावित किया गया
- Gross का मानना है कि
free-threadingभी बाहरी लोगों के लिए बहुत सहज नहीं है और यह बहुत प्रचलित term भी नहीं है - वास्तविक चर्चा में छोटे नामों की मजबूत पसंद दिखी, और उस दृष्टि से
nogilसबसे मजबूत उम्मीदवार था - ठोस रूप से जो बदलाव दिखा, वह no-GIL build के ABI tag को
nसेtमें बदलना थाtका मतलब threading है
abi4 प्रस्ताव और बाकी काम
- Gross और Viktorin ने API change proposal की समस्याओं पर चर्चा की, और उसी feedback से नए ABI abi4 का प्रस्ताव आगे बढ़ा
- Gross ने नए ABI का एक prototype बनाया है
- Viktorin का कहना है कि वे कुल मिलाकर इस approach से सहमत हैं, लेकिन details को अभी और साफ करना होगा
- Stinner का मानना है कि abi4 के लिए एक PEP चाहिए, जबकि Viktorin इसे pre-PEP discussion के रूप में देखते हैं
- limited C API version और
abi3के संयोजन से मिलने वाली compatibility guarantees को लेकर भ्रम है, और इसका असरabi4की दिशा पर भी पड़ता है - संबंधित जांच जारी है, और अक्टूबर के मध्य में core developer sprint के दौरान इस पर आमने-सामने चर्चा हो सकती है
अंतिम approval wording और दीर्घकालिक प्रभाव
- no-GIL या free-threaded CPython पर काम जारी है, लेकिन PEP 703 की अंतिम मंजूरी अभी लंबित है
- देरी कुछ लंबी हुई है, लेकिन PEP 703 और उसके प्रभाव आने वाले 5 साल या उससे अधिक समय तक CPython development और ecosystem पर बड़ा असर डाल सकते हैं
- steering council approval criteria को और स्पष्ट करना चाहती है
- Thomas Wouters ने कहा कि वे approval की सटीक wording को परिष्कृत कर रहे हैं और कई फैसलों को स्पष्ट करना चाहते हैं
- कुछ काम core developer sprint के दौरान भी आगे बढ़ सकता है
1 टिप्पणियां
Hacker News की राय
आधुनिक कंप्यूटरों को देखकर लगता है कि explicit parallelism शायद कंप्यूटर साइंस का उससे भी ज़्यादा बुनियादी हिस्सा हो सकता है जितना पाठ्यपुस्तकों में लोकप्रिय माना जाता है
शायद अब वह दौर है जहाँ हमें हमेशा स्पष्ट रूप से parallel code लिखना पड़ेगा
उदाहरण के लिए
forloop की जगहforeach,map,filterजैसी operations ले रही हैं। ये expressions compiler/interpreter को बताते हैं कि आप data structure के हर item पर कोई काम लागू करना चाहते हैं, और parallelize करना है या कैसे करना है, यह compiler/runtime पर छोड़ देते हैंweb service चलाने में हर request अपने-आप में काफी तेज़ होती है, और parallelism का असली फायदा बहुत सारी requests को साथ-साथ process करने में है। यहाँ No-GIL फिट बैठता है
अगर किसी single request के अंदर कई sub-requests हों, तो आम तौर पर उन्हें async code से handle किया जाता है, लेकिन अक्सर यह async के performance फायदे से ज़्यादा इसलिए होता है क्योंकि thread बनाना महँगा है या thread pool झंझट भरा है। async throughput के लिए अच्छा है, लेकिन latency के लिए खराब है, और अगर service request को parallelize कर रहे हों तो आम तौर पर latency की चिंता ज़्यादा होती है। async मुख्यतः usability की वजह से जीता
parallelism का एक और रूप बड़े offline jobs में दिखता है। MapReduce या Presto जैसी चीज़ें, और वे मोटे तौर पर divide-and-conquer problems जैसी दिखती हैं। GPU model training भी कुछ ऐसी ही है
जो नहीं हुआ, वह है local highly parallel algorithms। web services में data size छोटा होता है, इसलिए latency gain कम होता है, implementation जटिल होती है, और threads के बीच coordination cost बढ़ जाती है। एक छोटा अपवाद vectorized algorithms हैं, लेकिन वे एक core पर चलते हैं इसलिए coordination overhead नहीं होता, और online inference भी फिर से बहुत मजबूती से vectorized है
समय के साथ दोनों बेहतर हो रहे हैं। जैसे ज़्यादा languages और libraries default रूप से safe होती जा रही हैं, वैसे ही अब ज़्यादा चीज़ें default रूप से parallel हैं। अभी रास्ता बाकी है, लेकिन मुझे लगता है कि अच्छा हुआ हमने यह बहुत जल्दी नहीं किया। पिछले 10 सालों में technology काफी बेहतर हुई है
उदाहरण के लिए Rust के Rayon से सुरक्षित रूप से जो किया जा सकता है, उसकी तुलना C++ के OpenMP से असुरक्षित तरीके से किए जाने वाले काम से की जा सकती है
और बाहरी स्तर पर ये चीज़ें भी हैं जिन पर मैं काम करता हूँ: https://legion.stanford.edu/, https://regent-lang.org/, https://github.com/nv-legate/cunumeric
यह implementation detail है, इसलिए अगर इसे abstraction के ज़रिये आसान बनाया जा सकता है, तो ऐसा करना चाहिए
तुलना के लिए, mutex लगभग 25 nanoseconds का होता है और contention होने पर और बढ़ जाता है, लेकिन mutex point-to-point synchronization है
Disruptor की अच्छी बात यह है कि कई threads बिना बहुत अतिरिक्त effort के वही message पा सकते हैं
https://github.com/LMAX-Exchange/disruptor/wiki/Performance-...
https://gist.github.com/rmacy/2879257
मैं ऐसी भाषा का सपना देख रहा हूँ जो Smalltalk जैसी हो, लेकिन parallelization meaningful होने तक single-threaded बनी रहे
मैं big data नहीं, बल्कि parallelism की problems खोज रहा हूँ। parallelism कार की speed बढ़ाने से ज़्यादा सड़क पर और कारें डालने जैसा है। लेकिन अभी भी खोज रहा हूँ कि desktop या mobile user को locally computer की mathematical power का इस्तेमाल करके आखिर क्या करना चाहिए
parallelism ideas के रूप में Itanium और VLIW architectures के बारे में भी सोच रहा हूँ
-ngइस्तेमाल कर सकते हैं। मतलब no-gil या next-generationनया compiler flag, नया linker flag, अलग libraries link करना, यहाँ तक कि पूरी तरह अलग compiler command इस्तेमाल करना भी था। AIX खास तौर पर ऐसा था
shebang issue के लिए मौजूदा Python convention पर निर्भर रहना बेहतर लगता है:
from __future__ import nogilउस point पर interpreter को hot-swap कर देना चाहिए
from __future__ importकोई runtime statement नहीं, बल्कि flag बताने वाला special statement हैhttps://docs.python.org/3/reference/simple_stmts.html#future...
future statement module-level होता है, और GIL/no-GIL उस model में आसानी से फिट नहीं बैठता
इस प्रस्ताव को हर बार देखते हुए मुझे यह चिंता होती है कि कैसे सुनिश्चित किया जाएगा कि प्रोग्राम अब भी सही तरह से काम करें। मौजूदा multi-threaded Python code का काफी हिस्सा असुरक्षित तरीके से लिखा गया है
खासकर data races की समस्या है, जिसे मैंने कई कंपनियों के codebase और open source projects में बार-बार देखा है। ये programs सिर्फ इसलिए नहीं टूटते क्योंकि वे चुपचाप इस बात पर निर्भर करते हैं कि GIL एक समय में केवल एक thread को execute करने देता है
GIL हटने पर ऐसे programs टूटेंगे। Python एक dynamically typed language है, इसलिए मुझे बहुत संदेह है कि मौजूदा Python programs में ऐसी समस्याएं ढूंढने वाला कोई static analyzer मौजूद होगा
ज्यादा संभावना यह है कि runtime पर non-deterministically दिखने वाले subtle bugs आएंगे। काश वे crash कर दें, लेकिन इस तरह के bugs के गलत behavior करने में बदल जाने की संभावना ज्यादा है
शायद यह GIL-रहित प्रस्ताव ज्यादातर programs के लिए इस्तेमाल करने के लिए है ही नहीं। यह शायद उन बहुत कम परिस्थितियों के लिए एक बेहद specialized tool हो, जहां programmer जानता हो कि GIL नहीं है और उसी हिसाब से code लिख सके
GIL का मतलब सिर्फ इतना है कि एक समय में केवल एक thread Python bytecode execute कर सकता है। GIL वाला interpreter भी bytecodes के बीच thread switch कर सकता है, और कई Python operations के लिए कई bytecodes चाहिए होते हैं। इसमें built-in types के वे built-in methods भी शामिल हैं जिन्हें बहुत लोग “atomic” समझते हैं
इसलिए Python में आज GIL होने के बावजूद locks, mutexes, semaphores जैसी चीजें उपलब्ध हैं
GIL के लिए compete करने वाले threads पहले से ही खराब timing पर एक-दूसरे से GIL छीनकर गड़बड़ी पैदा कर सकते हैं
अगर program केवल तब GIL के बिना चले जब सभी dependencies इसकी अनुमति दें, तो ऐसे bugs ठीक करने के लिए काफी समय होगा
तो बड़े पैमाने पर इस समस्या से निपटना शायद 2030 के करीब जाकर होगा। अभी इस्तेमाल हो रहे runtime को latest release पर तुरंत upgrade करने वाले production systems भी ज्यादा नहीं दिखते
कठोर नहीं लगना चाहता, लेकिन Steering Council ने कहा है कि वे 2 से 3 जैसी एक और migration नहीं चाहते, इसलिए लोग हल्के में update नहीं करेंगे। अभी online मौजूद ज्यादातर सामग्री copy-paste करने के लिए जोखिमभरी हो सकती है
असली Python code में threading bugs बहुत ज्यादा हैं
क्या OCaml ने भी इसी तरह का evolution नहीं देखा? सोच रहा हूं कि दोनों projects के बीच तुलना करने लायक कुछ है या नहीं
इसलिए मौजूदा thread API मौजूदा domain के अंदर threads बनाता है और ऐसे code को isolate कर सकता है जो lock लिए जाने की उम्मीद करता है। नया code इसके बजाय एक thread से शुरू होने वाला नया domain बना सकता है। दोनों को जानबूझकर साथ में इस्तेमाल करके scheduling के रूप में भी उपयोग किया जा सकता है
Python libraries के authors के control से बाहर global तौर पर lock को पूरी तरह optional बनाने की कोशिश कर रहा है। हालांकि Python का lock केवल runtime को ही protect करता है, ऐसा guarantee किया हुआ लगता है, इसलिए उस lock पर निर्भर ज्यादातर code में वैसे भी bug होने की संभावना है, और इसलिए Python की योजना भी feasible लगती है
अगर कोई समानता है, तो बस इतनी कि पूरे runtime codebase में unexpected shared state ढूंढकर ठीक करनी होगी, और C ABI को revise करना होगा
अब Python को भी multi-threaded performance में Tcl की बराबरी करने का मौका मिल रहा है: https://www.hammerdb.com/blog/uncategorized/why-tcl-is-700-f...
मैं तो बेहतर समझूंगा कि Python code को Mojo में port करूं और multi-threading, SIMD, और दूसरी speed improvements हासिल करूं
Python code को nogil Python में नहीं ले जाना चाहते? तो downvote कर दो—कुछ ऐसा ही
नाम रखना हो तो
python4,python3-gilfoil,python3-gilfreeजैसे विकल्प हो सकते हैंइस समय GIL के बिना Python पर फोकस करने का रुख काफ़ी अजीब लगता है। Faster CPython टीम ने हर रिलीज़ में CPython की performance 50% बढ़ाने का महत्वाकांक्षी लक्ष्य रखा था
3.11 में वाकई सुधार हुए थे, लेकिन 50% से काफ़ी दूर थे, और हमारे कई tests में 3.12 लगभग वैसा ही था या और धीमा था। असली multithreading शानदार होगी, लेकिन पहले single-thread performance सुधरे, यह मैं कहीं ज़्यादा चाहता हूँ
बेशक, मैं मानता हूँ कि हमारी ज़रूरतें सभी का प्रतिनिधित्व नहीं कर सकतीं, और Python को बेहतरीन भाषा बनाने में लगे सारे काम के लिए आभारी हूँ। फिर भी जिज्ञासा है कि मैं क्या miss कर रहा हूँ
अभी कई cores का इस्तेमाल multiprocessing के ज़रिए होता है, जिसकी बहुत सीमाएँ हैं। मैं समझता हूँ कि कई interpreters, goroutines जैसी चीज़ों के साथ आ सकते हैं, लेकिन फिर भी मुझे असली multithreaded विकल्प ज़्यादा पसंद है
nogil Python में, उदाहरण के लिए, Python objects के रूप में accessible shared state रखते हुए कई threads C code को call कर सकते हैं। यह machine learning के लिए काफ़ी core है, और असल में इस PEP का मौजूदा रूप PyTorch टीम से आया था
single-thread performance भी अहम है, लेकिन critical sections के लिए पहले से ही numba, Cython, और Mojo जैसे काफ़ी अच्छे workarounds मौजूद थे
क्रम भी अहम है। अगर nogil आ जाता है, तो faster CPython के काम का बड़ा हिस्सा पूरी तरह फेंकना पड़ सकता है, इसलिए teams को coordinate करना पड़ा
ideal दुनिया में nogil mode और single-thread performance improvements दोनों होते। Guido ने भी इशारा किया था कि वे sophisticated JIT पर विचार कर रहे हैं
Python low-level abstractions को higher-level language से handle करना बहुत सुविधाजनक बना देता है। इसलिए लंबे समय से Python developer होने के नाते मुझे GIL को लेकर बहुत stress नहीं हुआ
अगर दोनों में से एक चुनना पड़े, तो मैं मानता हूँ कि ज़्यादातर use cases के लिए बस तेज़ single-threaded code बेहतर fit है। लेकिन दोनों रखने की कोई वजह भी नहीं कि क्यों न हों
hindsight में तो साफ़ दिखता है, लेकिन अगर Python side को पता होता कि 2 से 3 में transition कितना लंबा और दर्दनाक होगा, तो शायद interpreter internals में भी कहीं बड़े बदलाव किए जाते
12 साल के transition से गुजरने के बाद भी single-thread performance अब भी बेहद खराब है, और असली multithreading तक पहुँचने के लिए अभी भी कुछ दर्दनाक transitions बाकी हैं
पता है कि open source development के प्रति उदार होना चाहिए, लेकिन सोचता हूँ कि किस point के बाद इसे बहुत खराब तरीके से manage की गई language कहना ठीक होगा
Python के सबसे खराब हिस्से वे हैं जिन्हें बदलना मुश्किल है, क्योंकि Python बहुत ज़्यादा popular है और ecosystem बहुत बड़ा है। इसलिए backward compatibility के कारण हर तरह का बदलाव कठिन हो जाता है
Python का बचाव बहुत जल्दी करने की प्रवृत्ति है। bias के बिना objective तरीके से देखना ज़रूरी है
जिन projects को performance और Python syntax चाहिए, वे उस तरफ जा सकते हैं। मौजूदा Python कई लक्ष्यों के बीच हाथ-पैर मारता हुआ दिखता है और किसी को भी ठीक से हासिल नहीं कर पा रहा
Perl 5/6 को उदाहरण के तौर पर दिया गया था। जब यह साफ़ हो गया कि कोई transition नहीं कर रहा है, तब भी इसे आसान बनाने की कोशिशों तक लगभग 5 साल और लग गए