Kotlin coroutines nədir? nə üçün istifadə olunur? 1-ci hissə

Asinxron və Paralel proqramlaşdırma

Novruz Jafarov
4 min readMar 20, 2023

Coroutine-lər barədə danışmağa başlamadan öncə bu iki qavram arasındakı fərqi yaxşı başa düşməliyik.

Paralel proqramlaşdırma (Parallelism) — Bir işin paralel olaraq işlənəbiləcək daha kiçik işlərə bölünərək birdən çox cpu -da threadlər vasitəsilə işlənməsi mənasına gəlir. Paralel işlər məlumat və mənbə olaraq bir-birindən ayrı olduqları üçün sinxronizasiyaya ehtiyac duymurlar. Ən sadə misal olaraq, çox böyük ədədlərin faktorialını hesablayan bir proqramın yazılması üçün istifadə etmək olar. Real nümunə olaraq hər hansısa bir bazadan çoxlu sayda məlumatları oxuyacağımız halda həmin əmaliyyatı parçalara bölərək paralel şəkildə cəmləyə bilərik.

Asinxron proqramlaşdırma (Concurrency) — Bir proqramın eyni anda birdən çox əməliyyat üzərində işləməsi deməkdir. Uzun müddətli İO (İnput-Output) əməliyyatlarının cpu — nu bloklamasının qarşısını almaq üçün tətbiq edilir. Bir thread üzərində İO əməliyyatı yerinə yetirilən zaman, həmin thread-in bloklanmayaraq başqa əməliyyatlara yönləndirilməsi deməkdir. Bu metodun tətbiqi zamanı yaranan çətinlik, görülən işlər arasındakı sinxronizasiyanı uğurla yerinə yetirməkdir.

Kotlin proqramlaşdırma dili bu metodun tətbiqi üçün coroutine dediyimiz strukturu bizə təklif edir. Coroutine-lər görəcəyimiz işləri təmsil edir və dispatcher vasitəsilə ilə onlar arasındakı sinxronizasiyanı həyata keçiririk. Dispatcher, thread-lərin görüləcək işlər arasında bölüşdürülməsi işini həyata keçirir (context switch).

Coroutine nədir?

İndi isə coroutine-lər haqqında danışacağıq. İlk öncə onu qeyd etmək istərdimki coroutine-lər thread deyillər. Kotlin Coroutines — asinxron olaraq çalışmalı kod parçasını asanlaşdırmaq üçün istifadə olunan asinxron dizayn modelidir. Asinxron olaraq çalışan bir kod parçasının işlənməsi mövzsunda thread-lərə bənzəyirlər. Ancaq bir coroutine, müəyyən bir thread-ə bağlı deyildir. İşlənmə prosesini, bir thread-də gözləməyə ala bilər və başqa bir thread-də davam etdirə bilərlər. Beləliklə coroutine-lərə bir thread tərəfindən işlənilən iş parçaları kimi baxmaq olar. Suspend (Gözləmədə olan) olan bu işlər, bir thread üzərində gözləmədə olub, başqa bir thread üzərində işini davam etdirə bilərlər. Bunu CoroutineDispatcher idarə edir. CoroutineDispatcher bunun üçün suspend açar sözü istifadə edən xüsusi funksiyalardan istifadə edir.

Dependency əlavə olunması

Coroutine-ləri proqramımızda istifadə etmək üçün iki dependency (bağımlılıq) proqramımıza əlavə etməliyik:

dependencies {

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")

//For android
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
}

Suspend funksiyalar

Suspend funksiya dedikdə, başladılan, dayandırıla bilən və davam etdirilə bilən funksiyalar nəzərdə tutulur. Uzun müddət davam edən bir əməliyyatı (Məs: Fayl yükləmə, Http sorğu göndərmə, qəliz riyazı hesablamalar və s.) yerinə yetirə bilərlər və nəticəni heç bir bloklanma olmadan gözləyirlər. Bir suspend funksiya ancaq bir coroutine və ya başqa bir suspend funksiya tərəfindən çağırıla bilər. Bu funksiyalar haqqında bilinməsi ən vacib mövzulardan biri isə, sıralı şəkildə işləmələridir. Nümunə üçün aşağıdakı kod parçasına baxaq:

Delay funksiyası — Bir suspend funksiyanın thread-i bloklamadan, təyin etdiyimiz parametrə əsasən, müəyyən qədər gecikdirilməsinə imkan yaradır. Nümunəyə baxsaq buySomething() metoduna takeAMoney() metodundan daha az delay vermişik, amma yenədə metodlar arasındakı ardıcıllıq pozulmur. Bunun səbəbi suspend funksiyaların default olaraq ardıcıl şəkildə işləməsidir. Bu da bizim üçün asinxron proqramlaşdırma asanlaşdırır.

Arxa planda nə baş verir?

Nümunəmizdə olan buySomething(money: Double) metodu üzərindən davam edək. Metodumuz money adında bir parametr alırmış kimi görünsədə, əslində daxildə iki parametr alır. Daxildə bu funksiya, suspend açar sözü istifadə edilmədən və ikinci parametr kimi Continuation<T> tipində dəyər alan bir funksiyaya çevrilir.

fun buySomething(money: Double, continuation: Continuation)

Suspend funksiyaların bir-biri ilə əlaqə qurma üsulu bu continuation obyekti vasitəsilə həyata keçirilir. Continuation — müəyyən məlumatları özündə toplayan generic bir interfeysdir.

// Continuation interface structure
public interface Continuation<in T>
{
public val context: CoroutineContext
public fun resumeWith(result: Result<T>)
}
  • context — bu prosesdə istifadə ediləcək coroutine contexti
  • resumeWith — bir coroutine-nin geriyə cavab qayıdana qədərki işini davam etdirir və nəticə exception (xəta) və ya suspension(davam etmə) ola bilər.

Yeni bir coroutine yaratmaq

Bir coroutine-i başlatmaq üçün Kotlin standart kitabxanası, coroutine builder deyilən strukturlar yaratmışdır. Coroutine builder, müəyyən bir suspend funksiyanı əhatə edən və işləməsi üçün şərait yaradan metoddur. Gəlin bunlardan bir neçəsini tanıyaq:

CoroutineScope.Async

Bu scope, geriyə dəyər döndərən asinxron əməliyyatların icrası üçün istifadə olunur. Geriyə Deferred tipində bir dəyər döndərir. Deferred Javada olan Feature və ya Javascriptdə olan Promise qarşılığı kimi düşünə bilərik. Deferred nəticənin await() metodun çağırmaq vacibdir. Await bir suspend funksiyadır. Aşağıdakı nümunəmizə baxaq:

Nümunəmizdə, bir maşının video və şəkilini yükləmə prosesini simulyasiya etmişik. Gördüyümüz kimi async istifadə etdiyimiz funksiyalar bir birini gözləmir və yalnız gələn nəticəni gözləyirlər. Sonda isə nəticəni cəm şəkildə ekrana yazdırırıq.

CoroutineScope.Launch

Geriyə dəyər döndərmək vacib olmayan, arxa planda görüləcək işlər üçün istifadə olunan scope — dur. Aşağıdakı nümunəyə baxaq:

runBlocking

Adındanda göründüyü kimi, içərisində olan coroutine tamamlanana qədər, aid olduğu thread-i bloklayır. Coroutine içərisində istifadə edilməməlidir. Əsas istifadə sahəsi testingdir.

Qeyd: Kotlin developerləri, coroutine scope içərisində thread bloklayacak işlərin görülməsini məsləhət görmür. Bu səbəblə runBlocking-i coroutine scope içərisində istifadə etməkdən çəkinməliyik. Əgər runBlocking istifadə ediləcəksə, ən üst kod blokunda olmalıdır.

Birinci məqalənin sonunda kiçik bir faktorial hesablama proqramını coroutine ilə yazmağa çalışdıq və nəticə aşağıdakı kimi oldu:

Məqalənin ikinci hissəsində coroutine dispatcher nədir, contextlər arası keçidlər, dispatcher-lər arasındakı fərqlər, android tərəfində coroutine-lərin istifadəsi barədə danışacağıq.

--

--