runBlocking — Kotlin में एक Coroutine Builder जो पास्ड कोरूटीन के पूर्ण होने तक वर्तमान थ्रेड को ब्लॉक करता है। launch और async के विपरीत, यह suspend फ़ंक्शन नहीं है और सामान्य (blocking) कोड से बुलाया जा सकता है। JetBrains प्रदान, 2024 के अनुसार, runBlocking सिंक्रोनस और असिंक्रोनस दुनियाओं के बीच एक पुल के रूप में कार्य करता है, जो main फ़ंक्शन और परीक्षणों से कोरूटीन शुरू करने की अनुमति देता है।
मुख्य बातें
runBlocking एक Kotlin फ़ंक्शन है जो एक नया CoroutineScope बनाता है और पास्ड कोरूटीन को शुरू करता है, वर्तमान थ्रेड को तब तक ब्लॉक करता है जब तक वह पूर्णतः पूरा नहीं हो जाता। अन्य सभी Coroutine Builder के विपरीत, runBlocking एक suspend फ़ंक्शन नहीं है और सामान्य सिंक्रोनस कोड से बुलाया जा सकता है। runBlocking का हस्ताक्षर CoroutineContext और एक suspend ब्लॉक लेता है, जो T प्रकार का परिणाम लौटाता है।
public fun <T> runBlocking(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T
runBlocking वर्तमान थ्रेड पर एक नया event-loop शुरू करता है। जब कोरूटीन एक suspend फ़ंक्शन (जैसे delay() या await()) को कॉल करता है, runBlocking थ्रेड को ब्लॉक करता है और निलंबित कोरूटीन के फिर से शुरू होने तक उसी थ्रेड पर अन्य निर्धारित कोरूटीन को निष्पादित करता है। यह सहकारी ब्लॉकिंग है — थ्रेड निष्क्रिय नहीं होता बल्कि अन्य कोरूटीन को प्रोसेस करता है।
runBlocking का आंतरिक तंत्र event-loop पर आधारित है: जब कोई suspend फ़ंक्शन कॉल किया जाता है, runBlocking वर्तमान ब्लॉक के निष्पादन को रोक देता है और क्यू से अन्य कोरूटीन चलाता है। जब suspend फ़ंक्शन पूरा होता है, निष्पादन फिर से शुरू होता है। यह चक्र तब तक जारी रहता है जब तक सभी कोरूटीन समाप्त नहीं हो जातीं।
runBlocking कोरूटीन के निष्पादन के लिए अपना स्वयं का एकल-थ्रेड पूल उपयोग करता है। Dispatchers.IO या Default के विपरीत, runBlocking थ्रेड नहीं बदलता — यह सभी कोरूटीन को वर्तमान थ्रेड पर संचालित करता है, उनके निष्पादन को इंटरलेव करता है। यह एकमात्र बिल्डर है जो उसी थ्रेड पर निष्पादन की गारंटी देता है।
fun main() {
val threadName = Thread.currentThread().getName()
println("runBlocking से पहले $threadName पर")
val result = runBlocking {
println("runBlocking के अंदर ${Thread.currentThread().getName()} पर")
delay(500L)
"Done"
}
println("runBlocking के बाद: $result")
}
आउटपुट दिखाएगा कि तीनों println कथन एक ही थ्रेड पर निष्पादित होते हैं। runBlocking थ्रेड नहीं बदलता बल्कि event-loop का उपयोग करके एक ही थ्रेड के अंदर सहकारी मल्टिटास्किंग को व्यवस्थित करता है।
runBlocking तीन परिदृश्यों में उचित है: कंसोल एप्लिकेशन में main() प्रवेश बिंदु, suspend फ़ंक्शन के यूनिट परीक्षण और पुल — callback-आधारित या blocking लाइब्रेरियों से suspend कोड कॉल करना। प्रोडक्शन Android कोड में, मुख्य थ्रेड पर इसका उपयोग सदर निषिद्ध है।
| परिदृश्य | उपयोग्यता | जोखिम |
|---|---|---|
| main() कंसोल एप्लिकेशन का | हाँ | कोई नहीं — यह प्रवेश बिंदु है, थ्रेड UI को ब्लॉक नहीं करता |
| JUnit परीक्षण | हाँ | न्यूनतम — परीक्षण परिभाषा के अनुसार सिंक्रोनस होते हैं |
| Android UI थ्रेड | नहीं | ANR, लैग, इंटरफ़ेस फ्रीज़ |
| Callback → Coroutine | हाँ, सावधानी से | लंबे ऑपरेशनों में थ्रेड पूल ब्लॉकिंग |
Android परीक्षणों के लिए, runBlocking के बजाय kotlinx-coroutines-test का TestDispatcher के साथ उपयोग करें। यह समय नियंत्रण, स्वचालित सफाई और परीक्षण पृथक्करण प्रदान करता है।
अधिकांश परिदृश्यों में, runBlocking को असिंक्रोनस विकल्पों से बदला जा सकता है और बदलना चाहिए। Android के लिए, ये viewModelScope, lifecycleScope या उपयुक्त डिस्पैचर के साथ CoroutineScope हैं। परीक्षणों के लिए — TestCoroutineDispatcher और runTest।
// बुरा: Android मुख्य थ्रेड पर runBlocking
runBlocking(Dispatchers.Main) {
val result = networkApi.fetchData()
textView.setText(result)
}
// अच्छा: lifecycleScope
lifecycleScope.launch {
val result = withContext(Dispatchers.IO) { networkApi.fetchData() }
textView.setText(result)
}
परीक्षणों के लिए, बदलाव runTest है kotlinx-coroutines-test से। यह वास्तविक प्रतीक्षा के बिना विलंब का परीक्षण करने की अनुमति देने के लिए आभासी समय के साथ TestCoroutineScope बनाता है। यह परीक्षणों को तेज करता है और उन्हें निर्धार्यिक बनाता है।
सबसे सामान्य परिदृश्य suspend फ़ंक्शन का परीक्षण करना है। परीक्षणों में runBlocking आपको आर्किटेक्चर को बदले बिना एक कोरूटीन परिणाम की प्रतीक्षा करने की अनुमति देता है। दूसरा परिदृश्य callback API वाली लाइब्रेरियाँ हैं, जहाँ suspend फ़ंक्शन runBlocking के माध्यम से blocking संदर्भ से बुलाए जाते हैं।
// runBlocking के साथ suspend फ़ंक्शन का परीक्षण
class RepositoryTest {
@Test
fun `fetchUser returns correct data`() {
val repository = UserRepository(FakeApi())
val result = runBlocking {
repository.fetchUser("123")
}
assertEquals("John", result.name)
assertEquals("john@test.com", result.email)
}
}
callback और suspend दुनियाओं के बीच पुल के लिए, callbacks के बजाय runBlocking के साथ CompletableDeferred का उपयोग करें — यह असिंक्रोनस ऑपरेशन चेन को सरल करता है और कोड पठनीयता में सुधार करता है।
runBlocking का अनुचित उपयोग ब्लॉकिंग दृष्टिकोण से कोरूटीन में स्थानांतरित होते समय सामान्य गलतियों में से एक है। मुख्य समस्याएँ: Android के मुख्य थ्रेड पर कॉल करना, runBlocking को एक दूसरे के अंदर नेस्ट करना, असिंक्रोनस फ़ंक्शन के अंदर उपयोग करना और runBlocking के माध्यम से लंबे ऑपरेशन शुरू करना।
सुनहरी नियम: runBlocking एक पुल है, बदलाव नहीं। इसे केवल blocking और non-blocking दुनियाओं को जोड़ने के लिए उपयोग करें। अन्य सभी कार्यों के लिए, launch, async या lifecycleScope का उपयोग करें।
अक्सर पूछे जाने वाले प्रश्न
runBlocking एकमात्र बिल्डर है जो suspend फ़ंक्शन नहीं है। यह वर्तमान थ्रेड पर एक event-loop शुरू करता है और जब तक सभी कोरूटीन पूरी नहीं हो जातीं, नियंत्रण वापस नहीं करता। launch और async तुरंत नियंत्रण लौटाते हैं, कोरूटीन को पृष्ठभूमि में निष्पादित करते हैं।
अनुशंसित नहीं। ViewModel में एक निर्मित viewModelScope है जो स्वचालित रूप से कोरूटीन का प्रबंधन करता है और नष्ट होने पर उन्हें रद्द करता है। ViewModel में runBlocking थ्रेड को ब्लॉक करता है और लाइफसाइकल रद्दीकरण का जवाब नहीं देता।
kotlinx-coroutines-test लाइब्रेरी से runTest का उपयोग करें। यह आभासी समय नियंत्रण, स्वचालित रद्दीकरण और निर्धार्यिक निष्पादन के साथ TestCoroutineScope प्रदान करता है।
Event-loop runBlocking के अंदर एक ईवेंट प्रोसेसिंग चक्र है। जब कोई कोरूटीन निलंबित होती है (जैसे delay()), event-loop उसी थ्रेड पर अन्य तैयार कोरूटीन के निष्पादन पर स्विच करता है। यह थ्रेड स्विचिंग के बिना मल्टिटास्किंग का भ्रम पैदा करता है।
एक ही थ्रेड पर नेस्टेड runBlocking एक डेडलॉक बनाता है — बाहरी ब्लॉक आंतरिक का इंतजार करता है, लेकिन आंतरिक बाहरी के समाप्त होने तक शुरू नहीं हो सकता। अलग-अलग थ्रेड पर इसकी अनुमति है लेकिन डिबगिंग जटिलता के कारण दृढ़ता से हतोत्साहित नहीं है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें