Coroutines — əsas anlayışlar, Job və Dispatchers Kotlin-də

Müəllif: IT Sectr Dərc olunub: 2026-03-16 Oxuma vaxtı: 8 dəq

Coroutines (korutinlər) — kotlinx.coroutines kitabxanası vasitəsilə əldə edilən asinxron proqramlaşdırma üçün Kotlin-in yüngül thread-ləridir. JetBrains Kotlin Documentation, 2026-ya görə, Coroutines ənənəvi Thread-lərdən fərqli olaraq, funksiyanın icrasını thread-i bloklamadan dayandırmağa imkan verir. Korutinlər məhdud thread hovuzunda işlədilir və bu onları nativ thread-lərdən min dəfə yüngül edir. Kotlin Coroutines Android Jetpack, Retrofit, Room və Android ekosisteminin digər məşhur kitabxanaları ilə tam inteqrasiya olunub.

Əsas məqamlar

  • Coroutines — bloklanmadan asinxron kod üçün Kotlin-in yüngül thread-ləri
  • suspend funksiyası — thread-i bloklamadan dayandırılıb bərpa oluna bilən funksiya
  • Dispatcher korutinin icrası üçün thread hovuzunu müəyyən edir
  • Job — ləğvetmə və vəziyyət izləmə dəstəyi ilə korutin deskriptoru
  • CoroutineScope korutinlərin həyat dövrünü və onların tamamlandıqda ləğvini idarə edir

Kotlin korutinləri nədir

Coroutines (korutinlər) — kotlinx.coroutines kitabxanasında tətbiq olunan Kotlin-də asinxron proqramlaşdırma mexanizmidir. Əməliyyat sistemi thread-lərindən fərqli olaraq, korutinlər müəyyən bir thread-ə bağlı deyil: onlar bir thread-də dayanıb başqa bir thread-də bərpa oluna bilər. Bir thread minimal əlavə xərclə onların arasında keçid edərək minlərlə korutini icra edə bilər.

Korutinlər Kotlin 1.3-də (2018) eksperimental funksiya kimi ortaya çıxdı və Kotlin 1.5-də (2021) stabil oldu. Coroutines callback hell problemini async/await kimi həll edir, lakin daha zəngin API təqdim edir: kanallar (Channel), Flow, Job iyerarxiyasında istisna idarəetməsi və birbaşa Android Lifecycle ilə inteqrasiya.

JetBrains (2025) məlumatlarına görə, hər bir korutin nativ thread üçün 1+ MB-a qarşı təxminən 100 bayt yaddaş sərf edir. Bu, OutOfMemoryError riski olmadan bir tətbiqdə milyonlarla korutini işə salmağa imkan verir. Məhz korutinlərin yüngüllüyü onları Android-də asinxronluq üçün üstünlük verilən alət edir.

Korutinlər kapotun altında necə işləyir

Hər bir Kotlin korutini Continuation Passing Style (CPS) vasitəsilə state machine-ə kompilyasiya olunur. Kompilyator hər bir suspend funksiyasına gizli Continuation parametri əlavə edir. Continuation bərpa nöqtəsini və bütün lokal dəyişənləri ehtiva edir. Korutin dayandıqda, runtime Continuation-u saxlayır, bərpa olduqda isə onu Dispatcher hovuzundan istənilən mövcud thread-də bərpa edir.

Suspend funksiyaları: dayandırma və bərpa

suspend — funksiyanı dayandırıla bilən kimi qeyd edən Kotlin açar sözüdür. Belə bir funksiya yalnız başqa bir suspend funksiyasından və ya korutindən çağırıla bilər. Suspend funksiyasının daxilində digər suspend funksiyaları istənilən ardıcıllıqla çağırıla bilər və hər bir çağırış nöqtəsi potensial dayandırma nöqtəsidir.

Mexanika sadədir: suspend funksiyası başqa bir suspend funksiyasını çağırdıqda, o, thread-i boşaldaraq həmin nöqtədə dayanır. Çağırılan funksiya tamamlandıqdan sonra runtime qeyd olunmuş yerdən icranı davam etdirir. Buna cooperative cancellation deyilir — heç bir thread bloklanmır.

  • Dayandırma — korutin thread-i bloklamadan onu boşaldır
  • Bərpa — korutin dayandığı yerdən davam edir
  • Thread — korutin A thread-də dayanıb B thread-də bərpa oluna bilər
  • İstisnalar — sinxron koddakı kimi try/catch vasitəsilə idarə olunur

Vacib: suspend funksiyası standart olaraq asinxron deyil. İcra ardıcıllığı launch və ya async istifadə edilmədikdə seqvensial qalır. suspend yalnız funksiyanın thread-i bloklamadan dayandırılmasına və korutin kontekstinin bir hissəsi olmasına imkan verir. Continuation Passing Style hər bir suspend funksiyasının gizli Continuation callback-i aldığı və kompilyatorun dayandırmaları və bərpaları idarə etmək üçün vəziyyət maşını yaratdığı kompilyasiya modelidir.

CoroutineScope və Structured Concurrency

CoroutineScope — korutinlərin həyat dövrünü təyin edən kontekstdir. Bütün korutinlər scope daxilində işə salınmalıdır. Scope ləğv edildikdə (məsələn, Activity başa çatdıqda), onun bütün uşaq korutinləri avtomatik ləğv edilir. Bu, fon tapşırıqlarının sızmasının qarşısını alır. Android Jetpack hər bir komponent üçün hazır scope təqdim edir: ViewModel üçün viewModelScope və Activity və Fragment üçün lifecycleScope, müvafiq komponent məhv edildikdə avtomatik ləğv olunur.

Structured Concurrency — korutinin bütün uşaq korutinləri tamamlanana qədər bitməyəcəyinə zəmanət verən prinsipdir. Job iyerarxiyası bir ağac yaradır: kök korutin parent job, uşaqlar isə child jobs yaradır. Parent job-un ləğvi bütün uşaqlara yayılır. Structured Concurrency korutinlərlə thread-lər arasında əsas fərqdir.

ScopeHarada istifadə olunurLəğv
GlobalScopeYalnız daemon tapşırıqları üçünAvtomatik ləğv olunmur
viewModelScopeAndroid ViewModelViewModel təmizlənəndə
lifecycleScopeAndroid Activity/FragmentLifecycle məhv ediləndə
coroutineScopeSuspend funksiyası daxilindəParent job ləğv ediləndə

Səhv idarəetməsi üçün SupervisorJob

Adi Job bir uşaq korutində səhv olduqda bütün siblings-ləri ləğv edir. SupervisorJob — istisnadır: bir uşaq korutindəki nasazlıq qalanlarına təsir etmir. Bu, bir neçə müstəqil tapşırıq paralel icra edildikdə və onlardan biri digərlərini ləğv etməyə ehtiyac olmadan uğursuz ola bildikdə vacibdir.

Dispatchers və korutin qurucuları

Dispatchers korutinlərin hansı thread-lərdə icra olunacağını müəyyən edir. Dispatchers.Main — Android-in əsas UI thread-i. Dispatchers.IO — bloklayan əməliyyatlar üçün hovuz (şəbəkə, disk). Dispatchers.Default — CPU intensiv tapşırıqlar üçün. Dispatchers.Unconfined — cari thread-də başlayır, lakin orada qalacağına zəmanət vermir. Düzgün Dispatcher seçimi performans üçün kritikdir: Default-da IO tapşırığı hesablamalar üçün hovuzu bloklayacaq, IO-da CPU tapşırığı isə lazımsız thread-lər yaradacaq.

withContext — korutin daxilində Dispatcher-i dəyişmək üçün funksiya. Məsələn, JSON parse edən suspend funksiyası hesablama zamanı Dispatchers.Default-ə keçib UI yeniləməsi üçün Dispatchers.Main-ə qayıda bilər. withContext Android inkişafında ən çox istifadə olunan qurucudur.

Üç əsas korutin qurucusu

launch — korutini işə salır, Job qaytarır, nəticə qaytarmır (fire-and-forget). async — korutini işə salır, nəticəni await vasitəsilə əldə etmək üçün Deferred qaytarır. runBlocking — korutini icra etmək üçün cari thread-i bloklayır (yalnız testlər və main funksiyaları üçün). Qurucu seçimi ssenaridən asılıdır: launch hadisələr və yeniləmələr üçün, async nəticə ilə tapşırıqlar üçün, runBlocking yalnız testlər və ya giriş nöqtələri üçün uyğundur.

Kotlin-də korutinlərlə kod nümunələri

Üç praktik ssenariyə baxaq: launch ilə əsas korutin, async ilə paralel çağırış və SupervisorJob ilə səhv idarəetməsi.

Korutinin launch ilə işə salınması

viewModelScope.launch ViewModel kontekstində korutini işə salır. ViewModel təmizlənəndə korutin avtomatik ləğv edilir.

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

Async ilə paralel sorğular

coroutineScope async ilə üç sorğunu paralel işə salır. Nəticələr .await() vasitəsilə toplanır. Sorğulardan hər hansı biri uğursuz olarsa, hamısı ləğv edilir.

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

SupervisorJob ilə səhv idarəetməsi

SupervisorJob hər bir korutinin müstəqil başa çatmasına imkan verir. Bir sorğudakı səhv qalanlarını ləğv etmir.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

Korutinlər vs thread-lər: müqayisə və ssenarilər

Thread-lər — əməliyyat sistemi primitividir. Hər bir thread-in öz yığını (~1 MB) var və yaradılması və dəyişdirilməsi üçün sistem çağırışı tələb edir. Korutinlər — OS-yə bağlı olmayan dil primitividir. Vəziyyəti saxlamaq üçün Continuation-dan istifadə edir və sistem çağırışları olmadan runtime səviyyəsində dəyişilir.

  • Yaddaş — thread ~1 MB, korutin ~100 bayt. 10 000 dəfə fərq
  • Yaradılma — thread ~1 µs syscall, korutin ~0.01 µs JVM səviyyəsində
  • Dəyişmə — thread ~0.1 µs (syscall), korutin ~0.001 µs (continuation)
  • Maksimum — minlərlə thread vs cihazda milyonlarla korutin
  • Ləğv — thread kənardan ləğv edilə bilməz (deprecated Thread.stop), korutin Job.cancel() ilə ləğv edilə bilər

Google (2025) məlumatlarına görə, korutinlərin thread-lər əvəzinə istifadəsi Android tətbiqlərində fon tapşırıqları üçün yaddaş istehlakını 90–95% azaldır. Bütün müasir Android kitabxanaları (Retrofit, Room, WorkManager) suspend funksiyaları vasitəsilə korutinlər üçün daxili dəstəyə malikdir. Ktor (JetBrains-in HTTP klient framework-u) da tamamilə korutinlər üzərində qurulub, callback API olmadan hər sorğu üçün suspend-funksiyalar təqdim edir. Room DAO-da suspend-funksiyalar vasitəsilə korutinləri dəstəkləyir ki, bu da əsas thread-i bloklamadan verilənlər bazası sorğularını yerinə yetirməyə imkan verir.

Korutinlər əvəzinə thread-lər nə vaxt istifadə edilməlidir

Thread-lər JNI vasitəsilə nativ kod, vaxt məhdudiyyəti olmayan CPU intensiv bloklayan çağırışlar (video render, simulyasiyalar) və C kitabxanaları ilə inteqrasiya üçün zəruri olaraq qalır. Qalan hər şey üçün — korutinlər.

Tez-tez verilən suallar

Korutin thread-dən nə ilə fərqlənir?

Korutin — mövcud thread-də icra olunan dayandırıla bilən iş vahididir. Thread öz yığını olan sistem resursudur. Korutinlər thread-lərdən minlərlə dəfə yüngüldür və dayandırıldıqda resursları bloklamır.

Dispatchers.IO nədir və Default-dan nə ilə fərqlənir?

Dispatchers.IO bloklayan I/O əməliyyatları (şəbəkə, fayllar) üçün nəzərdə tutulub və lazım olduqda yeni thread-lər yarada bilər. Dispatchers.Default CPU intensiv hesablamalar üçün sabit ölçülü hovuza malikdir (prosessor nüvələrinin sayı).

İşə salınmış korutini necə ləğv etmək olar?

Job.cancel() korutini və onun bütün uşaqlarını ləğv edir. Korutin daxilində ləğvi yoxlamaq üçün ensureActive() istifadə edin — korutin ləğv edilibsə CancellationException atır.

Korutinləri RxJava ilə istifadə etmək olarmı?

Bəli — kotlinx-coroutines-rx3 kitabxanası vasitəsilə. Observable/Single-i suspend funksiyalarına və əksinə flowable vasitəsilə çevirmək üçün awaitSingle, awaitFirst və digər funksiyalar təqdim edir.

Korutinlərdə Flow nədir?

Flow — korutinlər üçün RxJava Observable-in analoqu olan soyuq asinxron məlumat axınıdır. Flow dəyərləri ardıcıl olaraq emit edir və istisna və ya uğurla başa çatır. Map, filter, catch və digər operatorları dəstəkləyir.

Nəticə

  • Coroutines — Continuation Passing Style vasitəsilə bloklanmadan dayandırma ilə Kotlin-in yüngül thread-ləri
  • suspend — dayandırıla bilən funksiyaları qeyd etmək üçün açar söz
  • Dispatchers thread hovuzunu idarə edir: Main, IO, Default müvafiq olaraq
  • CoroutineScope korutinlərin həyat dövrünü komponentə bağlayır (Activity, ViewModel)
  • launch nəticəsiz korutini işə salır, async/await — nəticə ilə
  • Structured Concurrency uşaq korutinlərin iyerarxik ləğvinə zəmanət verir
  • Korutinlər vs thread-lər — korutinlər 10 000 dəfə yüngüldür və Android üçün standartdır

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.

Layihəni müzakirə et

Həm də oxuyun