Rust में समवर्तीता: थ्रेड्स, गोरूटीन्स, async/await — पूर्ण विश्लेषण

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

Rust में समवर्तीता: म्यूटेक्स से async/await तक

\n\n

जब उच्च-प्रदर्शन प्रणालियों की बात आती है, तो Rust तुरंत ध्यान का केंद्र बन जाता है। लेकिन वास्तव में इसे अद्वितीय क्या बनाता है? यह है Rust में समवर्तीता — एक दृष्टिकोण जिसमें आपको C की गति और मेमोरी सुरक्षा मिलती है, बिना कोड की पठनीयता से समझौता किए। इस लेख में, हम तीन मुख्य उपकरणों पर चर्चा करेंगे: क्लासिकल थ्रेड्स, हल्के गोरूटीन्स (Rust के संदर्भ में — एसिंक्रोनस कार्य) और आधुनिक async/await। चलिए शुरू करते हैं!

\n\n

Rust समवर्तीता से क्यों नहीं डरता?

\n

कई भाषाओं के विपरीत, Rust कंपाइलर स्तर पर डेटा रेस की समस्या को हल करता है। स्वामित्व (ownership) और उधार (borrowing) प्रणाली गारंटी देती है कि आप गलती से दो थ्रेड्स से एक साथ डेटा नहीं बदल सकते। यह जादू नहीं है — यह सख्त स्थैतिक जाँच है। यही कारण है कि Rust में मल्टीथ्रेडिंग को सबसे सुरक्षित माना जाता है।

\n\n

1. थ्रेड्स (std::thread)

\n

क्लासिकल OS थ्रेड्स — यह आधार है। Rust में इन्हें मॉड्यूल std::thread के माध्यम से लागू किया गया है। प्रत्येक थ्रेड एक अलग हल्का प्रक्रिया है जो CPU के विभिन्न कोर पर समानांतर रूप से निष्पादित हो सकता है।

\n\n

उदाहरण: थ्रेड्स शुरू करना

\n
use std::thread;\nuse std::time::Duration;\n\nfn main() {\n    let handle = thread::spawn(|| {\n        for i in 1..10 {\n            println!("थ्रेड: {}", i);\n            thread::sleep(Duration::from_millis(1));\n        }\n    });\n\n    for i in 1..5 {\n        println!("मुख्य थ्रेड: {}", i);\n        thread::sleep(Duration::from_millis(1));\n    }\n\n    handle.join().unwrap();\n}
\n\n

यहाँ thread::spawn एक नया थ्रेड बनाता है, और join इसके पूरा होने की प्रतीक्षा करता है। सरल है, लेकिन एक बारीकी है: थ्रेड्स 'भारी' होते हैं। प्रत्येक थ्रेड कम से कम 2-8 MB स्टैक मेमोरी की खपत करता है। हजारों एक साथ कार्यों के लिए यह उपयुक्त नहीं है।

\n\n

थ्रेड्स का उपयोग कब करें?

\n
    \n
  • वास्तविक समानांतरता की आवश्यकता (CPU-बाउंड कार्य)।
  • \n
  • थ्रेड्स की संख्या कोर की संख्या * 2 से अधिक न हो।
  • \n
  • आप ब्लॉकिंग ऑपरेशन (फ़ाइल पढ़ना, सिंक्रोनस कॉल) के साथ काम कर रहे हैं।
  • \n
\n\n

2. Rust में गोरूटीन्स: मिथक या वास्तविकता?

\n

सख्ती से कहें तो, Rust में Go जैसे गोरूटीन्स नहीं हैं। लेकिन इसमें एसिंक्रोनस कार्य (tasks) हैं, जो लगभग उसी तरह व्यवहार करते हैं: वे हल्के होते हैं, सहकारी रूप से स्विच करते हैं (OS के बिना), और एक ही थ्रेड पर हजारों की संख्या में चलाए जा सकते हैं। इसके लिए रनटाइम Tokio या async-std का उपयोग किया जाता है।

\n\n

उदाहरण: Tokio के माध्यम से एसिंक्रोनस कार्य (गोरूटीन)

\n
use tokio::task;\n\n#[tokio::main]\nasync fn main() {\n    let handle = task::spawn(async {\n        for i in 1..10 {\n            println!("गोरूटीन: {}", i);\n            tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;\n        }\n    });\n\n    for i in 1..5 {\n        println!("मुख्य: {}", i);\n        tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;\n    }\n\n    handle.await.unwrap();\n}
\n\n

ध्यान दें: task::spawn एक हल्का कार्य बनाता है जो Tokio के थ्रेड पूल के भीतर निष्पादित होता है। मेमोरी लागत — प्रति कार्य लगभग 2-3 KB। यह बिना किसी समस्या के 100,000 'गोरूटीन्स' चलाने की अनुमति देता है। Go के विपरीत, यहाँ कोई अंतर्निहित शेड्यूलर नहीं है — आप स्वयं रनटाइम चुनते हैं।

\n\n

Rust के गोरूटीन्स Go से कैसे भिन्न हैं?

\n
    \n
  • Rust में — कार्य सहकारी हैं: वे स्वयं .await के माध्यम से नियंत्रण छोड़ते हैं।
  • \n
  • Go में — गोरूटीन्स प्रीएम्प्टिव हैं: शेड्यूलर I/O बिंदुओं पर उन्हें स्वयं बाधित करता है।
  • \n
  • Rust अधिक नियंत्रण देता है: आप सिंगल-थ्रेडेड या मल्टी-थ्रेडेड रनटाइम चुन सकते हैं।
  • \n
\n\n

3. Async/await: एसिंक्रोनस Rust का हृदय

\n

कीवर्ड async और .await सिंक्रोनस कोड को बिना किसी कठिनाई के एसिंक्रोनस में बदल देते हैं।

ब्लॉग

पुस्तक अनुशंसाएँ