Dispatchers Kotlin Coroutines में CoroutineContext के घटक हैं जो coroutines को निष्पादित करने के लिए थ्रेड निर्धारित करते हैं: Main (UI थ्रेड), IO (नेटवर्क और डिस्क), Default (CPU-गहन कार्य) और Unconfined (वर्तमान थ्रेड)। प्रत्येक डिस्पैचर कार्य के एक विशिष्ट प्रकार के लिए अनुकूलित एक विशेष थ्रेड पूल का प्रबंधन करता है। JetBrains गाइड, 2024 के अनुसार, सही डिस्पैचर चुनना एप्लिकेशन के प्रदर्शन और स्थिरता के लिए महत्वपूर्ण है।
मुख्य बिंदु
Dispatchers CoroutineDispatcher इंटरफ़ेस के कार्यान्वयन हैं, जो CoroutineContext के तत्व हैं। वे निर्धारित करते हैं कि coroutine किस थ्रेड या थ्रेड पूल पर निष्पादित होगा। launch या async के माध्यम से coroutine बनाते समय, डिस्पैचर को पहले पैरामीटर के रूप में पास किया जा सकता है: launch(Dispatchers.IO) { ... }. यदि कोई डिस्पैचर निर्दिष्ट नहीं है, तो यह बाहरी CoroutineScope से प्राप्त होता है।
Kotlin चार अंतर्निहित डिस्पैचर प्रदान करता है: Main, IO, Default, Unconfined। प्रत्येक डिस्पैचर संचालन के एक विशिष्ट प्रकार के लिए अनुकूलित अपने स्वयं के थ्रेड पूल का उपयोग करता है। सही डिस्पैचर चुनना एप्लिकेशन के प्रदर्शन को निर्धारित करता है: गलत विकल्प UI लैग, निष्क्रिय CPU कोर या अकुशल थ्रेड उपयोग की ओर ले जाता है।
| डिस्पैचर | थ्रेड पूल | अधिकतम थ्रेड | उपयोग |
|---|---|---|---|
| Dispatchers.Main | एक (UI) | 1 | UI अपडेट, LiveData, View |
| Dispatchers.IO | IO पूल | 64 (limitedParallelism) | नेटवर्क, फ़ाइलें, DB |
| Dispatchers.Default | CPU पूल | N कोर | सॉर्टिंग, पार्सिंग, गणना |
| Dispatchers.Unconfined | वर्तमान थ्रेड | N/A | मध्यवर्ती संचालन, परीक्षण |
Dispatchers.Main वह डिस्पैचर है जो Android मुख्य थ्रेड पर coroutines निष्पादित करता है। यह UI-संबंधित संचालन के लिए डिज़ाइन किया गया है: TextView अपडेट करना, notifyDataSetChanged कॉल करना, LiveData और StateFlow के साथ काम करना। Android में, यह डिस्पैचर Handler (Looper.getMainLooper()) के माध्यम से कार्यान्वित किया जाता है।
// Correct switch to Main for UI updates
viewModelScope.launch(Dispatchers.IO) {
val data = repository.fetchData()
withContext(Dispatchers.Main) {
_uiState.value = data
}
}
यदि कोई coroutine पहले से Main डिस्पैचर पर है, तो अतिरिक्त withContext(Dispatchers.Main) कोई ओवरहेड नहीं बनाता — डिस्पैचर वर्तमान थ्रेड की जाँच करता है और स्विच को छोड़ देता है। withContext डिस्पैचर के बीच स्विच करने का पसंदीदा तरीका है।
Dispatchers.IO एक डिस्पैचर है जो I/O संचालन के लिए अनुकूलित है: HTTP अनुरोध (Ktor, OkHttp), फ़ाइलों को पढ़ना और लिखना, Room या SQLDelight के साथ काम करना। यह डिफ़ॉल्ट रूप से 64 थ्रेड के पूल का उपयोग करता है, जो लोड के तहत स्केलेबल है। प्रत्येक नया I/O अनुरोध सीमा तक पहुँचने तक एक अतिरिक्त थ्रेड बना सकता है।
समवर्ती I/O संचालन की संख्या को नियंत्रित करने के लिए, limitedParallelism() का उपयोग करें। यह फ़ंक्शन समानांतर थ्रेड की संख्या पर सीमा के साथ एक नया डिस्पैचर बनाता है, जो बल्क संचालन के दौरान पूल को समाप्त होने से रोकता है।
val limitedIo = Dispatchers.IO.limitedParallelism(4)
// Load 100 files with limit of 4 concurrent operations
coroutineScope {
val files = (1..100).map { index ->
async(limitedIo) {
downloadFile("file_$index")
}
}
files.awaitAll()
}
सभी संचालनों के लिए IO डिस्पैचर का उपयोग करें जहाँ coroutine प्रतीक्षा में समय बिताता है (I/O-bound)। IO डिस्पैचर पर CPU-गहन कार्य अकुशल हैं — वे I/O के लिए इच्छित थ्रेड पर कब्जा कर लेते हैं, जिससे सिस्टम का थ्रूपुट कम हो जाता है।
Dispatchers.Default प्रोसेसर को लोड करने वाले कम्प्यूटेशन संचालन के लिए डिस्पैचर है: सॉर्टिंग, फ़िल्टरिंग, JSON पार्सिंग (Moshi, Kotlinx Serialization), इमेज प्रोसेसिंग, गणना। पूल का आकार प्रोसेसर कोर की संख्या के बराबर है (लेकिन 2 से कम नहीं)। यह संदर्भ स्विचिंग के बिना अधिकतम CPU उपयोग सुनिश्चित करता है।
suspend fun processData(input: List<RawRecord>): List<ProcessedRecord> {
return withContext(Dispatchers.Default) {
input
.parallelStream()
.map { transform(it) }
.toList()
}
}
I/O संचालन के लिए Dispatchers.Default का उपयोग न करें — यह CPU पूल के थ्रेड को ब्लॉक करेगा जो कम्प्यूटेशनल कार्यों को संसाधित कर सकते थे। IO और Default को अलग करना सिस्टम संसाधनों के इष्टतम उपयोग की अनुमति देता है: IO थ्रेड I/O की प्रतीक्षा करते हैं, CPU थ्रेड लगातार गणनाओं में व्यस्त रहते हैं।
Dispatchers.Unconfined एक विशेष डिस्पैचर है जो coroutine को किसी भी पूल से बाँधता नहीं है। Coroutine उस थ्रेड में निष्पादन शुरू करता है जहाँ launch/async कॉल किया गया था, और निलंबन के बाद उस थ्रेड में फिर से शुरू होता है जिसने resume कॉल किया था। यह व्यवहार मध्यवर्ती संचालन के लिए उपयुक्त है जिन्हें निश्चित संदर्भ की आवश्यकता नहीं होती है।
fun main() = runBlocking {
launch(Dispatchers.Unconfined) {
println("Before delay: ${Thread.currentThread().getName()}")
delay(500L)
println("After delay: ${Thread.currentThread().getName()}")
}
}
प्रोडक्शन कोड में, Dispatchers.Unconfined का उपयोग शायद ही कभी किया जाता है। मुख्य उपयोग के मामले: दूसरे डिस्पैचर में डेटा पास करने से पहले हल्के रूपांतरण और परीक्षण। प्रोडक्शन वर्कलोड के लिए, स्पष्ट डिस्पैचर का उपयोग करें — Unconfined अप्रत्याशित है क्योंकि निष्पादन थ्रेड resume कार्यान्वयन पर निर्भर करता है।
डिस्पैचर का चयन कार्य के प्रकार पर निर्भर करता है: UI संचालन → Main, I/O-bound → IO, CPU-bound → Default, मध्यवर्ती → scope से प्राप्त करें। Android के लिए, coroutine को उस डिस्पैचर पर लॉन्च करने की अनुशंसा की जाती है जहाँ मुख्य कार्य किया जाता है, और UI अपडेट करने से पहले withContext के माध्यम से Main पर स्विच करें।
जटिल परिदृश्यों के लिए, + ऑपरेटर का उपयोग करके डिस्पैचर को संयोजित करें: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. यह निर्दिष्ट डिस्पैचर, त्रुटि हैंडलिंग और पृथक Job पदानुक्रम के साथ एक CoroutineContext बनाता है।
अक्सर पूछे जाने वाले प्रश्न
Dispatchers.IO I/O-bound संचालन (I/O की प्रतीक्षा) के लिए 64 थ्रेड तक के पूल का उपयोग करता है, जबकि Dispatchers.Default कम्प्यूटेशनल कार्यों के लिए CPU कोर की संख्या के आधार पर पूल का उपयोग करता है। जब थ्रेड दुर्लभ होते हैं, तो दोनों पूल एक-दूसरे के साथ थ्रेड साझा कर सकते हैं।
हाँ, एकल-थ्रेड के लिए newSingleThreadContext() या फिक्स्ड पूल के लिए newFixedThreadPoolContext() का उपयोग करें। प्रोडक्शन के लिए, मौजूदा डिस्पैचर के आधार पर limitedParallelism() का उपयोग करें — यह नए पूल बनाने की तुलना में अधिक कुशल है।
यदि Dispatchers.Main उपलब्ध नहीं है (उदाहरण के लिए, JUnit परीक्षण या बैकग्राउंड सेवा में), तो IllegalStateException फेंका जाता है। परीक्षणों के लिए TestCoroutineDispatcher और बैकग्राउंड सेवाओं के लिए Dispatchers.IO या Default का उपयोग करें।
Dispatchers.IO.limitedParallelism(N) का उपयोग करें, जहाँ N समानांतर थ्रेड की अधिकतम संख्या है। यह बल्क अनुरोधों के दौरान पूल को समाप्त होने से रोकता है और नियंत्रित समानांतरता प्रदान करता है।
Dispatchers.Unconfined मध्यवर्ती संचालन के लिए उपयुक्त है: दूसरे डिस्पैचर में पास करने से पहले हल्के डेटा रूपांतरण, परीक्षण परिदृश्य। प्रोडक्शन Android कोड में, निलंबन के बाद अपरिभाषित निष्पादन थ्रेड के कारण इसकी अनुशंसा नहीं की जाती है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें