runBlocking — Kotlin tilidagi Coroutine Builder bo'lib, berilgan korutina tugaguncha joriy oqimni bloklaydi. launch va async dan farqli o'laroq, u suspend-funksiya emas va oddiy (bloklovchi) koddan chaqirilishi mumkin. JetBrains hujjatlariga ko'ra, 2024, runBlocking sinxron va asinxron dunyo o'rtasida ko'prik bo'lib xizmat qiladi, main-funksiyasi va testlardan korutinalarni ishga tushirishga imkon beradi.
Asosiy ma'lumotlar
runBlocking — Kotlin tilidagi funksiya bo'lib, yangi CoroutineScope yaratadi va berilgan korutinani ishga tushiradi, uning to'liq tugashigacha joriy oqimni bloklaydi. Boshqa barcha Coroutine Builder lardan farqli o'laroq, runBlocking suspend-funksiya emas va oddiy sinxron koddan chaqirilishi mumkin. runBlocking imzosi CoroutineContext va suspend-blokni qabul qiladi, T tipidagi natijani qaytaradi.
public fun <T> runBlocking(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T
runBlocking joriy oqimda yangi event-loop ishga tushiradi. Korutina suspend-funksiyani chaqirganda (masalan, delay() yoki await()), runBlocking oqimni bloklaydi va to'xtatilgan korutina qayta tiklanmaguncha xuddi shu oqimda boshqa rejalashtirilgan korutinalarni bajaradi. Bu kooperativ bloklash — oqim bo'sh turmaydi, balki boshqa korutinalarni qayta ishlaydi.
runBlocking ning ichki mexanizmi event-loop ga asoslangan: suspend-funksiya chaqirilganda, runBlocking joriy blokning bajarilishini to'xtatadi va navbatdan boshqa korutinalarni ishga tushiradi. Suspend-funksiya tugagach, bajarilish qayta tiklanadi. Bu sikl barcha korutinalar tugaguncha davom etadi.
runBlocking korutinalarni bajarish uchun o'zining bir oqimli havzasidan foydalanadi. Dispatchers.IO yoki Default dan farqli o'laroq, runBlocking oqimlarni almashtirmaydi — barcha korutinalarni joriy oqimda qayta ishlaydi, ularning bajarilishini navbatlashtiradi. Bu yagona bilder bo'lib, bir oqimda bajarilishni kafolatlaydi.
fun main() {
val threadName = Thread.currentThread().getName()
println("runBlocking dan oldin $threadName")
val result = runBlocking {
println("runBlocking ichida ${Thread.currentThread().getName()}")
delay(500L)
"Done"
}
println("runBlocking dan keyin: $result")
}
Natija shuni ko'rsatadiki, har uchala println bir oqimda bajariladi. runBlocking oqimni almashtirmaydi, balki event-loop orqali bir oqim ichida kooperativ ko'p vazifalilikni tashkil qiladi.
runBlocking uchta stsenariyda asoslangan: konsol ilovalarida main() kirish nuqtasi, suspend-funksiyalarning birlik testlari va ko'prik — callback asosidagi yoki bloklovchi kutubxonalardan suspend-kodni chaqirish. Android ishlab chiqarish kodida asosiy oqimda foydalanish qat'iy taqiqlangan.
| Stsenariy | Qo'llash mumkin | Xavflar |
|---|---|---|
| main() konsol ilovasi | Ha | Yo'q — bu kirish nuqtasi, oqim UI ni bloklamaydi |
| JUnit testlari | Ha | Minimal — testlar ta'rifiga ko'ra sinxrondir |
| Android UI-Thread | Yo'q | ANR, kechikishlar, interfeysning muzlashi |
| Callback → Coroutine | Ha, ehtiyotkorlik bilan | Uzoq muddatli operatsiyalarda oqim havzasining bloklanishi |
Android testlari uchun runBlocking o'rniga kotlinx-coroutines-test dan TestDispatcher bilan foydalaning. Bu vaqtni nazorat qilish, avtomatik tiklash va test izolyatsiyasini ta'minlaydi.
Aksariyat stsenariylarda runBlocking ni asinxron alternativlar bilan almashtirish mumkin va kerak. Android uchun bular viewModelScope, lifecycleScope yoki to'g'ri dispetcherli CoroutineScope. Testlar uchun — TestCoroutineDispatcher va runTest.
// Yomon: Android asosiy oqimida runBlocking
runBlocking(Dispatchers.Main) {
val result = networkApi.fetchData()
textView.setText(result)
}
// Yaxshi: lifecycleScope
lifecycleScope.launch {
val result = withContext(Dispatchers.IO) { networkApi.fetchData() }
textView.setText(result)
}
Testlar uchun almashtirish runTest kotlinx-coroutines-test kutubxonasidan. U virtual vaqt bilan TestCoroutineScope yaratadi, kechikishlarni real kutishsiz sinash imkonini beradi. Bu testlarni tezlashtiradi va ularni deterministik qiladi.
Eng keng tarqalgan stsenariy — suspend-funksiyalarni test qilish. Testlarda runBlocking korutina natijasini sinxron kutishga imkon beradi, arxitekturani o'zgartirmasdan. Ikkinchi stsenariy — callback API si bo'lgan kutubxonalar, bu erda suspend-funksiyalar runBlocking orqali bloklovchi kontekstdan chaqiriladi.
// Suspend funksiyasini runBlocking bilan test qilish
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 va suspend dunyosi o'rtasida ko'prik uchun callback lar o'rniga CompletableDeferred ni runBlocking bilan kombinatsiyada ishlating — bu asinxron operatsiyalar zanjirlarini soddalashtiradi va kod o'qilishini yaxshilaydi.
runBlocking dan noto'g'ri foydalanish bloklovchi yondashuvdan korutinalarga o'tishda eng keng tarqalgan xatolardan biridir. Asosiy muammolar: Android Main-Thread da chaqirish, runBlocking ni ichma-ich joylashtirish, asinxron funksiyalar ichida foydalanish va runBlocking orqali uzoq muddatli operatsiyalarni ishga tushirish.
Oltin qoida: runBlocking ko'prik, almashtirish emas. Faqat bloklovchi va bloklamaydigan dunyoni bog'lash uchun foydalaning. Barcha boshqa vazifalar uchun launch, async yoki lifecycleScope ni qo'llang.
Tez-tez beriladigan savollar
runBlocking suspend-funksiya bo'lmagan yagona bilderdir. U joriy oqimda event-loop ishga tushiradi va barcha korutinalar tugamaguncha boshqaruvni qaytarmaydi. launch va async darhol boshqaruvni qaytaradi, korutinani fonda bajaradi.
Tavsiya etilmaydi. ViewModel o'rnatilgan viewModelScope ga ega, u avtomatik korutinalarni boshqaradi va yo'q qilinganda ularni bekor qiladi. ViewModel da runBlocking oqimni bloklaydi va lifecycle bekor qilishiga reaksiya bermaydi.
runTest kutubxonasidan kotlinx-coroutines-test foydalaning. U virtual vaqt nazorati, avtomatik bekor qilish va deterministik bajarilish bilan TestCoroutineScope ta'minlaydi.
Event-loop — runBlocking ichida hodisalarni qayta ishlash sikli. Korutina to'xtatilganda (masalan, delay()), event-loop xuddi shu oqimda boshqa tayyor korutinalarni bajarishga o'tadi. Bu oqimlarni almashtirmasdan ko'p vazifalilik illyuziyasini yaratadi.
Bir oqimda ichma-ich runBlocking deadlock yaratadi — tashqi blok ichkini kutadi, lekin ichki tashqi tugamaguncha boshlanmaydi. Turli oqimlarda bu mumkin, ammo nosozliklarni tuzatish qiyinligi sababli qat'iy tavsiya etilmaydi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.