Channel, Kotlin Coroutines लाइब्रेरी से एक सिंक्रनाइज़ेशन प्रिमिटिव है जो कोरूटीन के बीच डेटा ट्रांसफर करने के लिए उपयोग होता है। Kotlin Documentation, 2025 के अनुसार, Channel suspend-फ़ंक्शन के माध्यम से ब्लॉकिंग भेजने के साथ producer-consumer पैटर्न लागू करता है। Channel Rendezvous, Buffered और Conflated मोड को सपोर्ट करता है, जिनमें से प्रत्येक ओवरफ़्लो होने पर व्यवहार निर्धारित करता है।
मुख्य बिंदु
Channel अवधारणात्मक रूप से Java के BlockingQueue के समान है, लेकिन ब्लॉकिंग put() और take() के बजाय suspend फ़ंक्शन send() और receive() के साथ। Kotlin डेवलपर साझा मेमोरी के माध्यम से सिंक्रनाइज़ेशन के बिना कोरूटीन के बीच डेटा आदान-प्रदान को व्यवस्थित करने के लिए Channel का उपयोग करता है। चैनल क्रमबद्ध डिलीवरी की गारंटी देता है — भेजने का क्रम प्राप्त करने के क्रम से मेल खाता है।
Channel बनाने के लिए फ़ैक्टरी फ़ंक्शन Channel<T>(capacity) को कॉल किया जाता है। पैरामीटर capacity चैनल प्रकार निर्धारित करता है: RENDEZVOUS (0), UNLIMITED (Int.MAX_VALUE), CONFLATED (-1) या कोई विशिष्ट संख्या। तत्व प्रकार T जेनेरिक के माध्यम से निर्दिष्ट किया जाता है। close() के माध्यम से चैनल बंद करना संकेत देता है कि कोई नया तत्व नहीं आएगा।
send(value) एक suspend फ़ंक्शन है जो चैनल भरा होने पर भेजने वाले कोरूटीन को निलंबित कर देता है। receive() एक suspend फ़ंक्शन है जो चैनल खाली होने पर प्राप्तकर्ता को निलंबित कर देता है। विकल्प trySend() और tryReceive() गैर-ब्लॉकिंग संस्करण हैं जो ऑपरेशन संभव न होने पर Boolean या null लौटाते हैं। ये गैर-suspend संदर्भों में उपयोगी हैं।
Kotlin बफ़र क्षमता के माध्यम से Channel के चार प्रकार प्रदान करता है: Rendezvous (क्षमता 0), Buffered (क्षमता N), Conflated (क्षमता 1, ओवरराइट) और Unlimited (क्षमता Int.MAX_VALUE)। प्रत्येक प्रकार अपना कार्य हल करता है, सख्त सिंक्रनाइज़ेशन से लेकर बड़े पैमाने पर डेटा बफ़रिंग तक।
Rendezvous Channel सबसे सख्त है: send() तब तक ब्लॉक रहता है जब तक किसी अन्य कोरूटीन में receive() न बुलाया जाए। संक्षेप में, यह दो कोरूटीन का मिलन बिंदु है। सख्त हैंडशेक के लिए आदर्श जब भेजने वाले को प्राप्तकर्ता द्वारा तत्व प्रसंस्करण की प्रतीक्षा करनी हो। डेटा हानि को बाहर रखा गया है — send तब तक पूरा नहीं होता जब तक receive निष्पादित न हो।
Conflated Channel केवल अंतिम भेजा गया मान संग्रहीत करता है। यदि भेजने वाला प्राप्तकर्ता के पुराना मान लेने से पहले नया तत्व डालता है, तो पुराना हटा दिया जाता है। Conflated Channel UI स्थिति के लिए उपयोगी है: यदि उपयोगकर्ता तेज़ी से स्लाइडर बदलता है, तो मध्यवर्ती मानों को हटाया जा सकता है और केवल अंतिम मान संसाधित किया जा सकता है।
Channel पर क्लासिक उत्पादक-उपभोक्ता पैटर्न समानांतर कोरूटीन के माध्यम से लागू किया जाता है। उत्पादक लूप में send(value) कॉल करता है, उपभोक्ता receive(value) कॉल करता है। उत्पादक और उपभोक्ता अलग-अलग Dispatchers पर काम कर सकते हैं: उत्पादक Dispatchers.IO पर, उपभोक्ता Dispatchers.Main पर। Channel Lock या synchronized के बिना स्वचालित रूप से एक्सेस को सिंक्रनाइज़ करता है।
Fan-out — एक चैनल पर कई उपभोक्ता। प्रत्येक तत्व ठीक एक उपभोक्ता को जाता है (round-robin वितरण)। Fan-in — कई उत्पादक एक चैनल में लिखते हैं। भेजने वाले कोरूटीन भेजने के लिए प्रतिस्पर्धा करते हैं, लेकिन तत्वों का क्रम संरक्षित रहता है। दोनों परिदृश्यों में अतिरिक्त सिंक्रनाइज़ेशन की आवश्यकता नहीं है।
Produce एक कोरूटीन बिल्डर है जो स्वचालित समापन के साथ चैनल बनाता है। फ़ंक्शन produce { } ReceiveChannel लौटाता है — उपभोक्ता के लिए केवल-पढ़ने योग्य चैनल। बिल्डर के अंदर send() डेटा भेजता है, और ब्लॉक पूरा होने या अपवाद होने पर चैनल स्वचालित रूप से बंद हो जाता है, लीक को रोकता है।
kotlinx.coroutines लाइब्रेरी select प्रदान करती है — एक अभिव्यक्ति जो कई विकल्पों में से पहले पूर्ण हुए चैनल की प्रतीक्षा करती है। Select कई चैनलों को मल्टीप्लेक्स करने की अनुमति देता है: उदाहरण के लिए, दो स्रोतों से डेटा की प्रतीक्षा करना और पहले उत्तर देने वाले को संसाधित करना। सिंटैक्स — select<T> { channel1.onReceive { } channel2.onReceive { } }। यह Rx में amb ऑपरेटर का विकल्प है।
पहला उदाहरण एक सरल Rendezvous Channel है जहाँ भेजने वाला प्राप्ति की प्रतीक्षा करता है:
val channel = Channel<String>()
scope.launch {
channel.send("Hello")
println("भेजा गया")
}
scope.launch {
val msg = channel.receive()
println("प्राप्त: $msg")
}
दूसरा उदाहरण — एक चैनल पर कई उपभोक्ता (fan-out):
val channel = Channel<Int>(Channel.UNLIMITED)
scope.launch {
for (x in 1..10) channel.send(x)
channel.close()
}
repeat(2) { id ->
scope.launch {
for (msg in channel) {
println("Consumer #$id: $msg")
}
}
}
तीसरा उदाहरण — त्रुटि प्रबंधन के साथ produce बिल्डर का उपयोग:
val source = produce {
for (i in 1..5) {
delay(200)
send(i)
}
}
scope.launch {
source
.consumeAsFlow()
.catch { println("त्रुटि: $it") }
.collect { println("तत्व: $it") }
}
Channel एक हॉट प्रिमिटिव है: डेटा सब्सक्राइबर्स से स्वतंत्र रूप से उत्सर्जित होता है। Flow कोल्ड है: डेटा सब्सक्रिप्शन पर उत्पन्न होता है। Channel प्रत्येक तत्व की एक उपभोक्ता को गारंटीकृत डिलीवरी के साथ कई उत्पादकों और उपभोक्ताओं (fan-out) को सपोर्ट करता है। Flow कई स्वतंत्र उत्पादकों के लिए डिज़ाइन नहीं किया गया है।
Channel बैकप्रेशर प्रबंधन के लिए कॉन्फ़िगरेबल क्षमता वाले बफ़र और suspend फ़ंक्शन send/receive का उपयोग करता है। Flow कोरूटीन के माध्यम से स्वचालित बैकप्रेशर के साथ suspend तंत्र collect का उपयोग करता है। Channel विशिष्ट परिदृश्यों के लिए एक निम्न-स्तरीय उपकरण है: कॉलबैक रूपांतरण, एक्टर मॉडल, कई भेजने वालों वाली कार्य कतार।
Android में दैनिक परिदृश्यों (UI स्थिति, DB से रिएक्टिव स्ट्रीम) के लिए Google Channel के बजाय Flow की अनुशंसा करता है। Channel का उपयोग तब किया जाना चाहिए जब सटीक बफ़र नियंत्रण के साथ कोरूटीन के बीच हॉट डेटा आदान-प्रदान की आवश्यकता हो, या callbackFlow के माध्यम से कॉलबैक इंटरफ़ेस कन्वर्ट करते समय, जिसका आंतरिक कार्यान्वयन Channel का उपयोग करता है।
एक महत्वपूर्ण व्यावहारिक उदाहरण: WebSocket क्लाइंट लागू करते समय, Channel एक कोरूटीन से संदेश लिखने और दूसरे से पढ़ने की अनुमति देता है जिसमें गारंटी है कि प्रत्येक संदेश ठीक एक बार संसाधित होगा। Flow इस कार्य के लिए उपयुक्त नहीं है क्योंकि यह कोल्ड है और कई उत्पादकों का समर्थन नहीं करता। UNLIMITED क्षमता वाला Channel सुनिश्चित करता है कि अस्थायी उपभोक्ता देरी के दौरान इनकमिंग संदेश खो न जाएं।
चैनल जीवनचक्र प्रबंधन Channel के साथ काम का एक महत्वपूर्ण हिस्सा है। जब सभी डेटा भेज दिया गया हो तो चैनल को बंद किया जाना चाहिए ताकि उपभोक्ता पुनरावृत्ति समाप्त कर सके। channel.close() कॉल करना संकेत देता है कि कोई नया तत्व नहीं आएगा। उपभोक्ता for (item in channel) के माध्यम से पुनरावृत्ति कर सकता है — close() और बफ़र खाली होने के बाद लूप स्वचालित रूप से समाप्त हो जाएगा। वैकल्पिक रूप से उपभोक्ता ClosedReceiveChannelException को संभालने के साथ लूप में receive() कॉल कर सकता है।
Channel Android में बिना निर्भरता के EventBus लागू करने के लिए सक्रिय रूप से उपयोग किया जाता है: Broadcast रणनीति वाला एक वैश्विक Channel<Event> एप्लिकेशन के किसी भी बिंदु से इवेंट भेजने की अनुमति देता है। LiveData-आधारित बसों के विपरीत, Channel जीवनचक्र से बंधा नहीं है और स्क्रीन के बीच संक्रमण करते समय सफाई की आवश्यकता नहीं है। ViewModel से send() और Activity/Fragment में lifecycleScope के माध्यम से receive() Event वर्गों के बिना टाइप-सुरक्षित संचार प्रदान करते हैं। Channel पर कई उपभोक्ता लोड वितरित करते हैं — प्रत्येक तत्व एक बार संसाधित होता है, जो विभिन्न सब्सक्राइबर्स में एकल इवेंट के डुप्लिकेट प्रसंस्करण को रोकता है।
एक्टर सिस्टम में Channel मेलबॉक्स — एक्टर के लिए संदेश कतार — लागू करने के आधार के रूप में कार्य करता है। एक एक्टर एक कोरूटीन है जो लूप में Channel से संदेश पढ़ता है और उन्हें क्रमिक रूप से संसाधित करता है। यह दृष्टिकोण गारंटी देता है कि प्रत्येक संदेश भेजने के क्रम में संसाधित होता है, बिना डेटा रेस के। Kotlin में एक प्रकार के रूप में अंतर्निहित एक्टर नहीं है (Akka के विपरीत), लेकिन Channel + launch एक हल्का विकल्प है।
द्विदिश आदान-प्रदान के लिए चैनल जोड़े का उपयोग किया जाता है: एक चैनल क्लाइंट से सर्वर तक अनुरोधों के लिए, दूसरा सर्वर से क्लाइंट तक प्रतिक्रियाओं के लिए। उदाहरण के लिए, मल्टीथ्रेडेड एप्लिकेशन में Pipe लागू करते समय: उत्पादक OutputChannel में लिखता है, उपभोक्ता InputChannel से पढ़ता है। suspend फ़ंक्शन send और receive गारंटी देते हैं कि उत्पादक-उपभोक्ता कॉल स्टैक को ओवरफ़्लो नहीं करेगा, क्योंकि कोरूटीन ब्लॉक होने के बजाय निलंबित होते हैं। BUFFERED क्षमता वाला Channel अधिकांश परिदृश्यों के लिए उपयुक्त है जहाँ उत्पादक और उपभोक्ता की गति लगभग बराबर है। असममित परिदृश्यों के लिए UNLIMITED का उपयोग करें ताकि उपभोक्ता व्यस्त होने पर उत्पादक निलंबित न हो — इससे डेडलॉक का जोखिम कम होता है लेकिन मेमोरी खपत बढ़ जाती है।
चैनलों पर आर्किटेक्चर डिज़ाइन करते समय capacity को याद रखना महत्वपूर्ण है: क्षमता का चुनाव सीधे पीक लोड के तहत व्यवहार को प्रभावित करता है। BUFFERED(N) क्षमता वाले चैनल एक स्मूथिंग बफ़र के रूप में कार्य करते हैं: यदि उपभोक्ता अस्थायी रूप से उत्पादक से धीमा है, तो तत्व जमा होते हैं। यदि उपभोक्ता की औसत गति लगातार उत्पादक से कम है, तो बफ़र भर जाएगा और भेजने वाला कोरूटीन निलंबित हो जाएगा — यह स्वचालित बैकप्रेशर है जो मेमोरी ओवरलोड से बचाता है।
Channel की निगरानी और डिबगिंग के लिए kotlinx-coroutines-debug का उपयोग करें: उपयोगिता सक्रिय कोरूटीन की संख्या, उनकी चैनल स्थिति (खुला/बंद, बफ़र में तत्वों की संख्या), और निलंबित send/receive संचालन का कॉल स्टैक दिखाती है। Channel को लॉगिंग प्रॉक्सी में भी लपेटा जा सकता है: LoggingChannel<T> वर्ग वास्तविक Channel को कॉल डेलीगेट करता है, send, receive और close संचालन लॉग करता है। यह चैनल लीक की पहचान करने में मदद करता है जब close() कॉल नहीं किया गया था और उपभोक्ता कोरूटीन हमेशा के लिए नए तत्वों की प्रतीक्षा कर रहा है।
अक्सर पूछे जाने वाले प्रश्न
Channel ब्लॉकिंग put() और take() के बजाय suspend फ़ंक्शन send() और receive() का उपयोग करता है। BlockingQueue के विपरीत, Channel ओवरफ़्लो होने पर थ्रेड को ब्लॉक नहीं करता — कोरूटीन निलंबित हो जाता है, अन्य कोरूटीन के लिए थ्रेड मुक्त करता है। Kotlin में कुशल थ्रेड उपयोग के लिए यह महत्वपूर्ण है।
बंद चैनल पर send() कॉल करने पर ClosedSendChannelException फेंका जाता है। भेजने से पहले isClosedForSend जांचें या trySend() का उपयोग करें जो बंद होने पर false लौटाता है। close() गारंटी देता है कि पहले से भेजे गए तत्व अपवाद फेंके जाने से पहले प्राप्त हो जाएंगे।
Conflated Channel उन इवेंट के लिए उपयोगी है जहाँ केवल नवीनतम स्थिति मायने रखती है — प्रोग्रेस बार, स्लाइडर स्थिति, स्पर्श निर्देशांक। यदि उपभोक्ता सभी इवेंट संसाधित नहीं कर सकता, तो मध्यवर्ती हटा दिए जाते हैं और नवीनतम गारंटीकृत रूप से संसाधित होता है। Conflated Channel की capacity=-1 है।
channel.close() कॉल करें — चैनल भेजने के लिए बंद के रूप में चिह्नित होता है, लेकिन पहले से भेजे गए तत्व receive() के माध्यम से पढ़े जाते रहते हैं। for (item in channel) के साथ पुनरावृत्ति बफ़र खाली होने के बाद स्वचालित रूप से समाप्त हो जाती है। isClosedForSend तुरंत true लौटाता है, isClosedForReceive खाली होने के बाद true लौटाता है।
हमेशा नहीं। Flow कोल्ड है — एक उत्सर्जन प्रति collect। यदि कई स्वतंत्र उत्पादकों को एक स्ट्रीम में लिखने की आवश्यकता है, तो Channel अनिवार्य है। दो कोरूटीन के बीच सरल डेटा ट्रांसफर के लिए Channel का उपयोग करें। डेटा के साथ रिएक्टिव स्ट्रीम के लिए Flow का उपयोग करें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें