परिचय: Rust में कार्य कतारों की आवश्यकता क्यों?
\n\nआधुनिक उच्च-लोड सिस्टम विकास में, कार्य कतारें (task queues) एक मौलिक पैटर्न हैं। वे कार्यों के निर्माण और उनके निष्पादन को अलग करने, लोड को संतुलित करने, वर्कर्स को स्केल करने और दोष-सहिष्णु अनुप्रयोग बनाने की अनुमति देते हैं। Rust, अपने सख्त मेमोरी नियंत्रण और गार्बेज कलेक्टर की अनुपस्थिति के साथ, कुशल कतारों को लागू करने के लिए अद्वितीय क्षमताएं प्रदान करता है।
\n\nइस लेख में, हम Rust में कार्य कतारों के साथ काम करने के तीन व्यावहारिक दृष्टिकोणों पर चर्चा करेंगे:
\n- \n
- मानक
mpsc(multi-producer, single-consumer) चैनलों का उपयोग; \n crossbeamलाइब्रेरी के साथ मल्टीथ्रेडेड कतारें; \n tokioपर एसिंक्रोनस कतारें। \n
प्रत्येक दृष्टिकोण के साथ स्पष्टीकरण सहित एक कार्यशील कोड उदाहरण होगा। आप सीखेंगे कि किसी विशिष्ट कार्य के लिए सही उपकरण कैसे चुनें और सामान्य गलतियों से कैसे बचें।
\n\n1. क्लासिक चैनल: std::sync::mpsc
\n\nRust की मानक लाइब्रेरी std::sync::mpsc मॉड्यूल प्रदान करती है — एक एकल उपभोक्ता के साथ एक मल्टीथ्रेडेड कतार। यह आदर्श विकल्प है जब आपके पास कई प्रोड्यूसर (थ्रेड जो कार्य भेजते हैं) और एक वर्कर (थ्रेड जो उन्हें निष्पादित करता है) हो।
सरल उदाहरण: एक वर्कर का पूल
\n\nuse std::sync::mpsc;\nuse std::thread;\nuse std::time::Duration;\n\nfn main() {\n // एक चैनल बनाएं: sender (प्रेषक) और receiver (प्राप्तकर्ता)\n let (tx, rx) = mpsc::channel::<String>();\n\n // एक वर्कर थ्रेड शुरू करें\n let worker = thread::spawn(move || {\n for task in rx {\n println!("[वर्कर] कार्य निष्पादित कर रहा हूँ: {}", task);\n thread::sleep(Duration::from_millis(500));\n println!("[वर्कर] कार्य '{}' पूर्ण हुआ!", task);\n }\n });\n\n // कई प्रोड्यूसर बनाएं (सरलता के लिए एक थ्रेड में)\n let producer = thread::spawn(move || {\n let tasks = vec![\n "फ़ाइल A को प्रोसेस करें",\n "ईमेल भेजें",\n "डेटाबेस अपडेट करें",\n "रिपोर्ट जनरेट करें",\n ];\n for task in tasks {\n println!("[प्रोड्यूसर] भेज रहा हूँ: {}", task);\n tx.send(task.to_string()).unwrap();\n thread::sleep(Duration::from_millis(200));\n }\n });\n\n producer.join().unwrap();\n // sender (tx) के नष्ट होने के बाद, receiver (rx) को None प्राप्त होगा और लूप समाप्त हो जाएगा\n drop(tx); // प्रोड्यूसर की ओर से चैनल बंद करें\n worker.join().unwrap();\n}\n\nविशेषताएं:
\n- \n
mpscचैनल बफ़र किया हुआ है — कार्य प्रेषक को तब तक ब्लॉक नहीं करते जब तक बफ़र भर न जाए। \n - केवल एक प्राप्तकर्ता — यह एक सीमा है, लेकिन यह सरलता और थ्रेड-सुरक्षा सुनिश्चित करता है। \n
- जब सभी प्रेषक विफल हो जाते हैं, तो चैनल स्वचालित रूप से बंद हो जाता है। \n
एकाधिक वर्कर: मैन्युअल वितरण
\n\nयदि आपको कई वर्कर्स की आवश्यकता है, तो mpsc सीधे उपयुक्त नहीं है। समाधान — एक चैनल और कई थ्रेड बनाना है जो कार्य प्राप्त करने के लिए प्रतिस्पर्धा करेंगे। हालाँकि, इसके लिए सावधानी की आवश्यकता है: Receiver Sync को लागू नहीं करता है, इसलिए इसे Mutex या Arc में लपेटना होगा।
use std::sync::{mpsc, Arc, Mutex};\nuse std::thread;\nuse std::time::Duration;\n\nfn main() {\n let (tx, rx) = mpsc::channel::<String>();\n let rx = Arc::new(Mutex::new(rx));\n\n let mut workers = vec![];\n for id in 0..3 {\n let rx = Arc::clone(&rx);\n let worker = thread::spawn(move || {\n loop {\n let task = {\n // म्यूटेक्स को कैप्चर करें और कार्य प्राप्त करें\n let rx = rx.lock().unwrap();\n rx.recv()\n };\n match task {\n Ok(task) => {\n println!("[वर्कर