runBlocking — Kotlin dilində Coroutine Builder-dir, verilən korutinanın tamamlanmasına qədər cari thread-i bloklayır. launch və async-dən fərqli olaraq, o suspend-funksiya deyil və adi (bloklayan) koddan çağırıla bilər. JetBrains sənədlərinə görə, 2024, runBlocking sinxron və asinxron dünya arasında körpü rolunu oynayır, main-funksiyasından və testlərdən korutinaları işə salmağa imkan verir.
Əsas məqamlar
runBlocking — Kotlin dilində yeni CoroutineScope yaradan və verilən korutinanı işə salan, onun tamamlanmasına qədər cari thread-i bloklayan funksiyadır. Bütün digər Coroutine Builder-lərdən fərqli olaraq, runBlocking suspend-funksiya deyil və adi sinxron koddan çağırıla bilər. runBlocking-in imzası CoroutineContext və suspend-blok qəbul edir, T tipli nəticə qaytarır.
public fun <T> runBlocking(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T
runBlocking cari thread-də yeni event-loop işə salır. Korutina suspend-funksiya çağırdıqda (məsələn, delay() və ya await()), runBlocking thread-i bloklayır və dayandırılmış korutina bərpa olunana qədər eyni thread-də digər planlaşdırılmış korutinaları icra edir. Bu kooperativ bloklamadır — thread boş dayanmır, digər korutinaları emal edir.
runBlocking-in daxili mexanizmi event-loop-a əsaslanır: suspend-funksiya çağırıldıqda, runBlocking cari blokun icrasını dayandırır və növbədən digər korutinaları işə salır. Suspend-funksiya tamamlandıqda icra bərpa olunur. Bu dövr bütün korutinalar tamamlanana qədər davam edir.
runBlocking korutinaları icra etmək üçün öz təkthreadli hovuzundan istifadə edir. Dispatchers.IO və ya Default-dan fərqli olaraq, runBlocking thread-ləri dəyişmir — bütün korutinaları cari thread-də emal edir, onların icrasını növbələşdirir. Bu, eyni thread-də icraya zəmanət verən yeganə bilderdir.
fun main() {
val threadName = Thread.currentThread().getName()
println("runBlocking-dən əvvəl $threadName")
val result = runBlocking {
println("runBlocking daxilində ${Thread.currentThread().getName()}")
delay(500L)
"Done"
}
println("runBlocking-dən sonra: $result")
}
Nəticə göstərəcək ki, hər üç println eyni thread-də icra olunur. runBlocking thread-i dəyişmir, əksinə event-loop vasitəsilə bir thread daxilində kooperativ çoxtapşırıqlılıq təşkil edir.
runBlocking üç ssenaridə əsaslandırılmışdır: konsol tətbiqlərində main() giriş nöqtəsi, suspend-funksiyaların vahid testləri və körpü — callback əsaslı və ya bloklayan kitabxanalardan suspend-kodun çağırılması. Android-in production-kodunda əsas thread-də istifadə qəti qadağandır.
| Ssenari | Tətbiq oluna bilər | Risk |
|---|---|---|
| main() konsol tətbiqi | Bəli | Yoxdur — bu giriş nöqtəsidir, thread UI-ni bloklamır |
| JUnit testləri | Bəli | Minimal — testlər tərifinə görə sinxrondur |
| Android UI-Thread | Xeyr | ANR, gecikmələr, interfeysin donması |
| Callback → Coroutine | Bəli, ehtiyatla | Uzun müddətli əməliyyatlarda thread hovuzunun bloklanması |
Android testləri üçün runBlocking əvəzinə kotlinx-coroutines-test kitabxanasından TestDispatcher istifadə edin. Bu, vaxta nəzarət, avtomatik sıfırlama və test izolyasiyası təmin edir.
Əksər ssenarilərdə runBlocking asinxron alternativlərlə əvəz edilə bilər və edilməlidir. Android üçün bunlar viewModelScope, lifecycleScope və ya düzgün dispetçerli CoroutineScope-dur. Testlər üçün — TestCoroutineDispatcher və runTest.
// Pis: Android əsas thread-də runBlocking
runBlocking(Dispatchers.Main) {
val result = networkApi.fetchData()
textView.setText(result)
}
// Yaxşı: lifecycleScope
lifecycleScope.launch {
val result = withContext(Dispatchers.IO) { networkApi.fetchData() }
textView.setText(result)
}
Testlər üçün əvəz runTest-dir kotlinx-coroutines-test kitabxanasından. O, virtual vaxt ilə TestCoroutineScope yaradır, gecikmələri real gözləmə olmadan test etməyə imkan verir. Bu testləri sürətləndirir və determinist edir.
Ən çox yayılmış ssenari — suspend-funksiyaların test edilməsidir. Testlərdə runBlocking korutinanın nəticəsini sinxron gözləməyə imkan verir, arxitekturanı dəyişmədən. İkinci ssenari — callback API-si olan kitabxanalardır, burada suspend-funksiyalar runBlocking vasitəsilə bloklayan kontekstdən çağırılır.
// Suspend funksiyasını runBlocking ilə test et
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 və suspend dünyası arasında körpü üçün callback-lər əvəzinə CompletableDeferred-i runBlocking ilə kombinasiyada istifadə edin — bu, asinxron əməliyyat zəncirlərini sadələşdirir və kodun oxunaqlılığını artırır.
runBlocking-in yanlış istifadəsi bloklayan yanaşmadan korutinalara keçid zamanı ən çox rast gəlinən səhvlərdən biridir. Əsas problemlər: Android Main-Thread-də çağırış, runBlocking-in iç-içə yerləşdirilməsi, asinxron funksiyalar daxilində istifadə və runBlocking vasitəsilə uzun müddətli əməliyyatların işə salınması.
Qızıl qayda: runBlocking körpüdür, əvəz deyil. Yalnız bloklayan və bloklamayan dünyanı birləşdirmək üçün istifadə edin. Bütün digər tapşırıqlar üçün launch, async və ya lifecycleScope tətbiq edin.
Tez-tez verilən suallar
runBlocking suspend-funksiya olmayan yeganə bilderdir. O, cari thread-də event-loop işə salır və bütün korutinalar tamamlanana qədər nəzarəti qaytarmır. launch və async dərhal nəzarəti qaytarır, korutinanı fonda icra edir.
Tövsiyə edilmir. ViewModel daxili viewModelScope-ə malikdir, o avtomatik korutinaları idarə edir və məhv olduqda ləğv edir. ViewModel-də runBlocking thread-i bloklayır və lifecycle ləğvinə reaksiya vermir.
runTest kitabxanasından kotlinx-coroutines-test istifadə edin. O, virtual vaxta nəzarət, avtomatik ləğv və deterministik icra ilə TestCoroutineScope təmin edir.
Event-loop — runBlocking daxilində hadisələrin emal dövrüdür. Korutina dayandırıldıqda (məsələn, delay()), event-loop eyni thread-də digər hazır korutinaların icrasına keçir. Bu, thread-ləri dəyişmədən çox tapşırıqlılıq illüziyası yaradır.
Bir thread-də iç-içə runBlocking deadlock yaradır — xarici blok daxili gözləyir, lakin daxili xarici tamamlanana qədər başlaya bilməz. Müxtəlif thread-lərdə bu mümkündür, lakin debug çətinliyi səbəbindən qəti tövsiyə edilmir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun