स्विफ्ट में समवर्तीता: थ्रेड्स, गोरूटीन्स और async/await — कैसे पागल न हों

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

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

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

परिचय: जब आप फ़ीड स्क्रॉल कर रहे होते हैं तो आपका iPhone क्यों नहीं हैंग होता?

\n\n

क्या आपने कभी सोचा है कि आधुनिक iOS ऐप्स तब भी धीमे क्यों नहीं होते, जब वे एक साथ दर्जनों चित्र लोड कर रहे हों, टैप प्रोसेस कर रहे हों और डेटाबेस में डेटा लिख रहे हों? इसका उत्तर सरल है — समवर्तीता। Swift (और न केवल) की दुनिया में यह सबसे गर्म विषयों में से एक है। और यदि आप Swift में लिखते हैं, लेकिन फिर भी थ्रेड्स, गोरूटीन्स और नए async/await में भ्रमित हो जाते हैं — तो क्लब में आपका स्वागत है। आज हम सब कुछ स्पष्ट कर देंगे, ताकि आपका कोड उड़े, न कि रेंगे।

\n\n

इस लेख में हम केवल सूखी परिभाषाएँ सूचीबद्ध नहीं करेंगे। हम वास्तविक उदाहरण देखेंगे, दृष्टिकोणों की तुलना करेंगे और मुख्य प्रश्न का उत्तर देंगे: अपने प्रोजेक्ट के लिए क्या चुनें — पुराना अच्छा GCD या नया Swift Concurrency?

\n\n\n\n

थ्रेड्स: वह नींव जिस पर सब कुछ टिका है

\n\n

आधार से शुरू करते हैं। थ्रेड प्रसंस्करण की सबसे छोटी इकाई है जिसे ऑपरेटिंग सिस्टम निष्पादित कर सकता है। एक कन्वेयर बेल्ट की कल्पना करें: एक थ्रेड — एक लाइन जिस पर कार्य चलते हैं। यदि आपके पास एक सिंगल-कोर प्रोसेसर है, तो थ्रेड बारी-बारी से निष्पादित होंगे, लेकिन बहुत तेज़ी से स्विच करते हुए, समानता का भ्रम पैदा करेंगे। मल्टी-कोर प्रोसेसर पर, थ्रेड वास्तव में समानांतर रूप से निष्पादित हो सकते हैं।

\n\n

Swift में लंबे समय तक थ्रेड्स के साथ काम करने का मुख्य उपकरण Grand Central Dispatch (GCD) था। आप बस एक कतार बनाते थे और उसमें एक क्लोज़र भेजते थे:

\n\n
DispatchQueue.global(qos: .background).async {\n    // पृष्ठभूमि में भारी काम\n    let result = heavyComputation()\n    DispatchQueue.main.async {\n        // मुख्य थ्रेड पर UI अपडेट करना\n        self.label.text = result\n    }\n}
\n\n

सरल है, है ना? लेकिन GCD में कुछ बारीकियाँ हैं:

\n
    \n
  • आप स्वयं मुख्य थ्रेड पर वापस आने के लिए जिम्मेदार हैं (इसे भूलना आसान है और क्रैश हो सकता है)।
  • \n
  • कार्यों को रद्द करने का कोई अंतर्निहित समर्थन नहीं है (फ़्लैग मैन्युअल रूप से लिखने पड़ते हैं)।
  • \n
  • क्लोज़र्स के नेस्टिंग के बिना निर्भर संचालन की श्रृंखलाओं को संसाधित करना कठिन है (तथाकथित "callback hell")।
  • \n
\n\n

फिर भी, GCD आज भी जीवित है और लीगेसी प्रोजेक्ट्स में उपयोग किया जाता है। लेकिन आधुनिक Swift कहीं अधिक सुरुचिपूर्ण कुछ प्रदान करता है।

\n\n

Swift में गोरूटीन्स? नहीं, यह Go नहीं है

\n\n

जब गोरूटीन्स की बात होती है, तो आमतौर पर Go याद आता है। Swift में गोरूटीन्स का कोई सीधा एनालॉग नहीं है, लेकिन हल्के-फुल्के कार्य (tasks) हैं, जो बहुत समान व्यवहार करते हैं। वे किसी विशिष्ट थ्रेड से बंधे नहीं होते — सिस्टम स्वयं तय करता है कि कार्य को किस थ्रेड पर निष्पादित करना है, और प्रत्येक कॉल के लिए नए थ्रेड बनाए बिना उन्हें थ्रेड्स के बीच स्विच कर सकता है।

\n\n

थ्रेड्स के विपरीत, जिनमें से प्रत्येक का स्टैक लगभग 8 KB होता है, Swift Concurrency के कार्य व्यावहारिक रूप से कुछ भी नहीं लेते हैं। आप मेमोरी को ओवरफ्लो करने के जोखिम के बिना हजारों कार्य चला सकते हैं। यही वह "बिना दर्द के समवर्तीता" है।

\n\n

देखें यह कैसा दिखता है:

\n\n
Task {\n    let image = await downloadImage(from: url)\n    await MainActor.run {\n        self.imageView.image = image\n    }\n}
\n\n

ध्यान दिया? कोई DispatchQueue.main.async नहीं। बस await MainActor.run। साफ, समझने योग्य, सुरक्षित।

\n\n

async/await: वह क्रांति जो हुई

\n\n

Swift 5.5 के आगमन के साथ, async/await के लिए अंतर्निहित समर्थन आया। यह केवल सिंटैक्टिक शुगर नहीं है — यह प्रतिमान बदलाव है। अब आप एसिंक्रोनस कोड इस तरह लिख सकते हैं जैसे कि वह सिंक्रोनस हो, लेकिन थ्रेड को ब्लॉक किए बिना।

\n\n

एक एसिंक्रोनस फ़ंक्शन घोषित करना सरल है:

\n\n
func fetchUserData() async throws -> User {\n    let url = URL(string: "https://api.example.com/user")!\n    let (data, _) = try await URLSession.shared.data(from: url)\n    return try JSONDecoder().decode(User.self, from: data)\n}
\n\n

और इसे कॉल करना और भी सरल है:

\n\n
Task {\n    do {\n        let user = try await fetchUserData()\n        print("User nam                

ब्लॉग

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