भविष्य को आकार देने वाली तकनीक पर गहन लेख।

Pyodide: WebAssembly से ब्राउज़र में असली Python चलाएँ

Pyodide CPython को WebAssembly में कंपाइल करता है, जिससे NumPy और pandas के साथ Python सीधे ब्राउज़र में चलता है। यह कैसे काम करता है और कहाँ उपयोगी है।

एक घूमता हुआ Python साँप, ब्राउज़र विंडो के आकार के कांच के टेरेरियम के अंदर, साथ में विज्ञान के क्रेट

ब्राउज़र में Python चलाना 2010 के शुरुआती दौर से एक सपना रहा है, और हर कोशिश में एक ही दिक्कत आई: Python, CPython के C रनटाइम से इतनी गहराई से जुड़ा है कि उसे वेब एनवायरनमेंट में आसानी से पोर्ट नहीं किया जा सकता। Transcrypt, Brython और Skulpt ने Python को JavaScript में दोबारा लिखकर इसे हल करने की कोशिश की। सरल स्क्रिप्ट्स के लिए यह चल गया, लेकिन जैसे ही NumPy, pandas या C एक्सटेंशन वाली लाइब्रेरीज़ की ज़रूरत पड़ी, जिनकी वजह से Python सच में काम का बनता है, सब टूट गया।

Pyodide एक अलग रास्ता लेता है: असली CPython इंटरप्रेटर को WebAssembly में कंपाइल करो। यह कोई दोबारा लिखा हुआ वर्शन नहीं है, बल्कि असली CPython सोर्स कोड है, जिसे Emscripten से ब्राउज़र में चलाने लायक बनाया गया है। इसका मतलब है पूरी भाषा की compatibility, C एक्सटेंशन समेत। आप import numpy लिख सकते हैं और यह काम करता है, क्योंकि कंपाइल किए गए Wasm बाइनरी में NumPy का असली C कोड शामिल होता है।

Pyodide अंदर से कैसे काम करता है

Pyodide की build प्रक्रिया CPython सोर्स ट्री को लेकर Emscripten से कंपाइल करती है। Emscripten एक compiler toolchain है जो नेटिव मशीन कोड की जगह WebAssembly को टारगेट करता है। नतीजा एक .wasm बाइनरी होता है, जिसमें Python इंटरप्रेटर लागू होता है, और साथ में JavaScript glue code होता है जो उसे ब्राउज़र एनवायरनमेंट से जोड़ता है।

असली पेचीदगी C एक्सटेंशन में है। उदाहरण के लिए, NumPy में 1 लाख से ज़्यादा लाइनों का C और Fortran कोड है। Pyodide NumPy, pandas, scikit-learn, matplotlib, scipy जैसे चुनिंदा लोकप्रिय पैकेजों को पहले से Wasm मॉड्यूल में कंपाइल करके रखता है, जिन्हें ज़रूरत पड़ने पर लोड किया जा सकता है। जब आप import numpy चलाते हैं, तो Pyodide पहले से कंपाइल किया NumPy Wasm मॉड्यूल डाउनलोड करता है, उसे चल रहे इंटरप्रेटर से लिंक करता है और उसे इनिशियलाइज़ करता है।

<!-- Minimal Pyodide example -->
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.js"></script>
<script>
async function main() {
// Load the Python interpreter (~10MB download)
const pyodide = await loadPyodide();
// Run Python code directly
pyodide.runPython(`
import sys
print(f"Python {sys.version} running in the browser!")
`);
// Load packages on demand
await pyodide.loadPackage('numpy');
// Use NumPy — the real NumPy, compiled to Wasm
const result = pyodide.runPython(`
import numpy as np
arr = np.random.randn(1000)
f"Mean: {arr.mean():.4f}, Std: {arr.std():.4f}"
`);
console.log(result);  // "Mean: 0.0123, Std: 1.0045"
}
main();
</script>

JavaScript-Python ब्रिज

Pyodide की सबसे मज़बूत खूबियों में से एक है Python और JavaScript के बीच सहज interop। Python ऑब्जेक्ट्स अपने-आप JavaScript में proxy हो जाते हैं और उलटा भी। आप Python से JavaScript फंक्शन कॉल कर सकते हैं, Python से DOM बदल सकते हैं, और बिना मैनुअल serialization के दोनों भाषाओं के बीच डेटा भेज सकते हैं।

// JavaScript calling Python
const pyodide = await loadPyodide();
// Define a Python function
pyodide.runPython(`
def analyze(data):
import statistics
return {
'mean': statistics.mean(data),
'median': statistics.median(data),
'stdev': statistics.stdev(data)
}
`);
// Call it from JavaScript with JS data
const analyze = pyodide.globals.get('analyze');
const result = analyze([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
console.log(result.toJs());  // {mean: 5.5, median: 5.5, stdev: 3.03}
// Python accessing the DOM
pyodide.runPython(`
from js import document
element = document.getElementById('output')
element.textContent = 'Updated from Python!'
`);

Proxy सिस्टम टाइप कन्वर्ज़न अपने-आप संभालता है: Python dict JavaScript object बन जाते हैं, Python lists JavaScript arrays बन जाते हैं, और Python numbers JavaScript numbers बन जाते हैं। बड़े डेटा ट्रांसफर के लिए, जैसे दस लाख एलिमेंट वाला NumPy array किसी JavaScript visualization library को देना, Pyodide कॉपी से बचने के लिए shared memory buffers इस्तेमाल करता है, और परफ़ॉर्मेंस के लिए यह बहुत अहम है।

Pyodide कहाँ काम का है

Interactive computing environments. Pyodide पर बना JupyterLite Jupyter notebooks को पूरी तरह ब्राउज़र में चलाता है। कोई सर्वर नहीं चाहिए, Python kernel Wasm में लोकल चलता है। शिक्षा के लिए यह बड़ा बदलाव है: छात्र बिना कुछ इंस्टॉल किए Python notebooks चला सकते हैं, और शिक्षक को सर्वर प्रोविज़न करने की ज़रूरत नहीं पड़ती।

Data exploration tools. ऐसी वेब एप्लिकेशन जहाँ यूज़र डेटा अपलोड करके उस पर analysis चलाते हैं, वे Pyodide से डेटा को पूरी तरह client-side प्रोसेस कर सकते हैं। डेटा ब्राउज़र से बाहर नहीं जाता, जिससे privacy की चिंता खत्म होती है और सर्वर का खर्च भी बचता है। जो CSV uploader ब्राउज़र में pandas transformations चलाता है, वह उस uploader से सरल deploy होता है और ज़्यादा private भी, जो डेटा को backend पर भेजता है।

Live examples वाला documentation. Python लाइब्रेरी के documentation में ऐसे interactive code blocks हो सकते हैं जो सच में चलते हैं। स्टैटिक आउटपुट दिखाने की जगह पाठक कोड बदलकर तुरंत नतीजे देख सकते हैं। सीखने के लिए यह स्टैटिक उदाहरणों से कहीं ज़्यादा असरदार है।

Prototyping और experimentation. Python में सोचने वाले data scientists ब्राउज़र में ही data transformations और visualizations का prototype बना सकते हैं, फिर नतीजा एक URL के रूप में शेयर कर सकते हैं। न environment setup, न dependency management, न 'मेरी मशीन पर तो चल रहा था' वाली दिक्कतें।

परफ़ॉर्मेंस की असली तस्वीर

Pyodide तेज़ नहीं है। नेटिव कोड की तुलना में WebAssembly में ओवरहेड होता है, कंप्यूट-भारी कामों में आम तौर पर 1.5-3 गुना धीमा। ऊपर से Pyodide, Wasm में कंपाइल हुआ CPython चलाता है, जो पहले से ही शुद्ध Python कोड के लिए C से लगभग 100 गुना धीमा है। शुद्ध Python loops में Pyodide, नेटिव CPython से लगभग 2-5 गुना धीमा है।

लेकिन बात यह है कि जिन कामों में Pyodide उपयोगी है, उनमें ज़्यादातर समय C एक्सटेंशन कॉल्स में जाता है, शुद्ध Python में नहीं। जब आप np.dot(a, b) चलाते हैं, तो असली गणना कंपाइल किए गए C कोड में होती है (जो अब Wasm में कंपाइल है)। उस C कोड पर Wasm का ओवरहेड 1.5-3 गुना है, जो इंटरैक्टिव इस्तेमाल के लिए बिल्कुल ठीक है। एक NumPy matrix multiplication जो नेटिव रूप से 10ms लेता है, Pyodide में 20ms लेता है। notebook में 'Run' दबाने वाले यूज़र को यह फ़र्क महसूस भी नहीं होगा।

Performance comparison (approximate):
Native CPython    Pyodide (Wasm)
Pure Python loop:     1x                3-5x slower
NumPy operations:     1x                1.5-3x slower
Pandas groupby:       1x                2-3x slower
Startup time:         50ms              2-5 seconds
Package loading:      instant (pip)     2-10s (download + init)
Startup is the real cost. Once loaded, interactive
performance is adequate for most use cases.

असली समस्या स्टार्टअप कॉस्ट है। Pyodide का core runtime लोड करने के लिए लगभग 10MB डाउनलोड होता है। NumPy जोड़ने पर 7MB और, और pandas पर 10MB और। जिस वेब पेज को जल्दी render होना है, उसके लिए 5 सेकंड की initialization देरी एक dealbreaker है। इसीलिए Pyodide उन एप्लिकेशन में सबसे अच्छा चलता है जहाँ यूज़र को environment लोड होने का इंतज़ार करने की उम्मीद हो, जैसे notebooks, data tools और इंटरैक्टिव tutorials, न कि पारंपरिक वेब पेज।

Pyodide क्या नहीं कर सकता

हर Python पैकेज Pyodide में नहीं चलता। जिन पैकेजों की system dependencies हों, जैसे database drivers, GUI libraries, या OS-specific APIs को कॉल करने वाली कोई भी चीज़, वे Wasm में कंपाइल नहीं होंगे। psycopg2 को PostgreSQL client library चाहिए। opencv को system graphics libraries चाहिए। ये dependencies ब्राउज़र एनवायरनमेंट में मौजूद ही नहीं हैं।

नेटवर्किंग भी सीमित है। Python का socket module ब्राउज़र में काम नहीं करता, Wasm से raw socket access संभव नहीं है। HTTP requests Pyodide के JavaScript bridge के ज़रिए ब्राउज़र के fetch() API से जाती हैं, इसलिए वे CORS restrictions के अधीन हैं। Pyodide में Flask server नहीं चलाया जा सकता (सुनने के लिए कोई socket नहीं है), और मनमाने network connections भी नहीं बनाए जा सकते।

Threading Web Workers के ज़रिए आंशिक रूप से सपोर्टेड है, लेकिन Python का GIL (Global Interpreter Lock) फिर भी लागू होता है, और threading model नेटिव CPython से अलग है। CPU-bound parallelism के लिए threads की जगह multiprocessing बेहतर काम करता है (हर worker को अपना Wasm instance मिलता है)।

Pyodide बनाम Transpiled Python

Pyodide के तरीके (CPython को Wasm में कंपाइल करना) की तुलना उस दूसरे तरीके से करना दिलचस्प है जिसमें Python को JavaScript में transpile किया जाता है। Transcrypt और Brython जैसे प्रोजेक्ट Python syntax को JavaScript में बदलते हैं, और नतीजा ब्राउज़र के JS engine में सीधे चलता है।

Transpilation रनटाइम पर तेज़ है, क्योंकि जनरेट हुआ JavaScript नेटिव JS स्पीड पर चलता है, Wasm-CPython स्पीड पर नहीं। इसकी स्टार्टअप कॉस्ट भी शून्य है, क्योंकि कोई रनटाइम डाउनलोड नहीं करना होता। लेकिन इसकी कीमत compatibility है: transpiled Python C एक्सटेंशन नहीं चला सकता, CPython से कुछ सूक्ष्म semantic अंतर रखता है (खासकर numeric types, string handling और edge cases में), और standard library के सिर्फ़ एक हिस्से को सपोर्ट करता है।

Pyodide की ताकत यह है कि वह असली CPython चलाता है। अगर आपका Python कोड CPython में चलता है, तो वह Pyodide में भी चलेगा (सिस्टम-स्तर की dependencies को छोड़कर)। NumPy, pandas और scikit-learn पर निर्भर data science workflows के लिए यह compatibility बेहद ज़रूरी है। बिना C एक्सटेंशन वाली सरल स्क्रिप्ट्स के लिए transpilation बेहतर विकल्प हो सकता है। जैसा किसी भी Wasm बनाम नेटिव-JS तुलना में होता है, सही टूल workload पर निर्भर करता है।

आगे क्या है

Pyodide सक्रिय रूप से विकसित हो रहा है और बेहतर हो रहा है। हाल के versions में core runtime का आकार घटा है, streaming compilation से स्टार्टअप समय सुधरा है (ब्राउज़र डाउनलोड होते-होते ही Wasm compile करने लगता है), और पहले से कंपाइल पैकेजों का दायरा बढ़ा है। WebAssembly इकोसिस्टम भी परिपक्व हो रहा है: WASI standardized system interfaces देता है, और component model Wasm मॉड्यूल्स के बीच बेहतर interop सक्षम करेगा।

बड़ा रुझान यह है कि ब्राउज़र एक universal runtime बनता जा रहा है। JavaScript, Wasm और Pyodide जैसे प्रोजेक्ट्स के बीच, लगभग किसी भी भाषा में लिखा कोड सीधे ब्राउज़र में चल सकता है। इससे server-side computing की जगह नहीं आती, बल्कि जो computation सर्वर की ज़रूरत नहीं रखता, उसे क्लाइंट की तरफ़ ले जाकर यह उसका पूरक बनता है। Python के विशाल data science इकोसिस्टम के लिए, ब्राउज़र में client-side चलना ऐसे उपयोग के मामले खोलता है जो पहले संभव ही नहीं थे।