withContext: nədir, kontekst dəyişməsi və korutinalarda işləmə

Müəllif: IT Sectr Dərc olunub: 2026-06-22 Oxuma vaxtı: 9 dəq

withContext — korutina daxilində icra kontekstini dəyişən funksiyadır, müvəqqəti olaraq göstərilən kod bloku üçün thread və ya dispatcher-i dəyişir və nəticəni orijinal kontekstə qaytarır. JetBrains, 2025 məlumatlarına görə, withContext şəbəkə sorğuları və disk əməliyyatları üçün korutinaların ən çox istifadə olunan alətlərindən biridir. Funksiya blok tamamlandıqdan sonra korutinanın orijinal dispatcher-də icranı davam etdirəcəyinə zəmanət verir ki, bu da təsadüfi thread təhlükəsizliyi səhvlərinin qarşısını alır.

Əsas məqamlar

  • withContext — verilmiş kod bloku üçün CoroutineContext-i dəyişən və nəticə qaytaran dayandırıcı funksiyadır
  • Dispatchers.IO — şəbəkə və disk əməliyyatlarında fon thread-ə keçmək üçün tipik arqumentdir
  • Dispatchers.Main — withContext-in blok bitdikdən sonra icranı avtomatik qaytardığı orijinal kontekstdir
  • Ardıcıl çağırışlar — withContext kodu launch və async-dən fərqli olaraq ardıcıl icra edir ki, bu da əməliyyat sırasına nəzarəti asanlaşdırır
  • Val nəticəsi — withContext lambda-nın son sətirində return vasitəsilə birbaşa dəyər qaytarır, await və ya join olmadan

Kotlin-də withContext nədir?

withContext — kotlinx.coroutines paketindən dayandırıcı funksiyadır, verilmiş kod blokunu müəyyən CoroutineContext-də icra edir və nəticəni orijinal kontekstə qaytarır. Funksiyanın imzası belə görünür:

kotlin
suspend fun  withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T

context parametri istənilən CoroutineContext qəbul edir — ən çox standart Dispatchers.IO, Dispatchers.Default və ya Dispatchers.Main-dən biri. Blok məhz bu kontekstdə icra olunur və nəticə withContext-in çağırıldığı yerə qaytarılır.

Əsas xüsusiyyət: avtomatik qayıdış

Lambda tamamlandıqdan sonra withContext zəmanətli şəkildə icranı orijinal dispatcher-ə qaytarır. Bu o deməkdir ki, tərtibatçı fon əməliyyatından sonra əl ilə withContext(Dispatchers.Main) çağırmalı deyil — qayıdış avtomatik baş verir. Bu davranış Kotlin Coroutines spesifikasiyasında 1.3 versiyasından etibarən təsbit edilmişdir.

withContext harada tətbiq olunur

Android inkişafı — withContext-in əsas tətbiq sahəsidir. Tipik ssenari: ViewModel əsas thread-də korutina işə salır, daxilində şəbəkə sorğusu üçün withContext(Dispatchers.IO) çağırılır və nəticə Main-ə avtomatik qayıtdıqdan sonra UI-ni yeniləmək üçün istifadə olunur. Bu yanaşma MVVM arxitekturasının əsasını təşkil edir və Google tərəfindən korutinalar üzrə rəsmi bələdçidə tövsiyə olunur.

withContext necə işləyir: dispatcher-lərin dəyişdirilməsi

withContext-i başa düşmək üçün CoroutineContext və onun əsas komponenti olan dispatcher-i (Dispatcher) anlamaq lazımdır. Hər bir korutinanın kontekst elementləri dəsti var, onların arasında dispatcher kodun hansı thread və ya thread hovuzunda icra olunacağını müəyyən edir.

withContext üçün standart dispatcher-lər

DispatcherTəyinatHovuz ölçüsü
Dispatchers.MainƏsas UI thread (Android, JavaFX, Swing)1 (əsas thread)
Dispatchers.IODisk və şəbəkə əməliyyatları64 thread (limit artır)
Dispatchers.DefaultCPU intensiv hesablamalarmax(2, nüvə sayı)
Dispatchers.UnconfinedSabit thread olmadanməhdud deyil

withContext-in yeni korutina yaratmadığını başa düşmək vacibdir — o, mövcud olan üçün yalnız konteksti dəyişir. Bu, onu launch və async-dən fərqləndirən əsas xüsusiyyətdir, çünki onlar yeni korutinalar yaradır. Daxili tətbiq optimallaşdırılıb: tələb olunan kontekst cari ilə üst-üstə düşərsə, dəyişiklik baş vermir — funksiya eyni dispatcher-də icra olunur.

withContext thread-i NƏ ZAMAN dəyişmir

Dispatchers.Main withContext(Dispatchers.Main) daxilində dəyişikliyə səbəb olmur — Kotlin Coroutines kontekstlərin eyniliyini tanıyır və lazımsız əməliyyatı buraxır. Eynilə, artıq Default-da işləyən korutina daxilində withContext(Dispatchers.Default) heç bir əlavə yük yaratmır. Bu optimallaşdırma ContinuationInterceptor-da tətbiq edilmişdir.

withContext vs launch və async: nə vaxt nəyi seçmək

Yeni başlayanlar tez-tez withContext-i launchasync ilə qarışdırır, çünki hər üç funksiya korutinalar və kontekstlə işləyir. Lakin onların təyinatı prinsipial olaraq fərqlidir.

Üç funksiyanın müqayisəsi

XüsusiyyətwithContextlaunchasync
Yeni korutina yaradırXeyrBəliBəli
Nəticə qaytarırBəli (T birbaşa)Xeyr (Job)Bəli (Deferred<T>)
İcraArdıcılParalelParalel
Nəticəni gözləməAvtomatikjoin()await()
Tipik istifadəDispatcher dəyişməFire-and-forgetParalel hesablamalar

Seçim qaydası

Fon thread-də bir əməliyyat yerinə yetirib nəticə almaq lazımdırsa — withContext istifadə edin. Bir neçə müstəqil əməliyyatı paralel işə salmaq lazımdırsa — async ilə await istifadə edin. Nəticə lazım deyilsə (loglama, cache yazma) — launch. Google Android arxitekturasında Repository qatı üçün withContext-i üstünlük verilən alət kimi tövsiyə edir.

withContext ilə kod nümunələri

Kotlin dilində Android tətbiqlərində withContext-in üç praktik ssenarisini nəzərdən keçirək. Hər bir nümunə konkret tapşırığı və düzgün nümunəni göstərir.

Nümunə 1: Repository-də şəbəkə sorğusu

ViewModel korutinadan Main-də repository metodunu çağırır. Daxildə withContext(Dispatchers.IO) HTTP sorğusunu icra edir və nəticə avtomatik qaytarılır:

kotlin
class UserRepository(
    private val api: UserApi
) {
    suspend fun getUser(id: String): User {
        return withContext(Dispatchers.IO) {
            api.fetchUser(id)
        }
    }
}

ViewModel-dəki korutina getUser-i adi dayandırıcı funksiya kimi çağırır — dispatcher-i açıq şəkildə göstərmədən. withContext thread dəyişdirmə detallarını gizlədir.

Nümunə 2: İki ardıcıl fon əməliyyatı

Bir neçə IO əməliyyatını bir-birinin ardınca yerinə yetirmək lazım olduqda, withContext onları vahid blokda birləşdirir. Bu, hər əməliyyatı ayrıca withContext-ə yerləşdirməkdən daha səmərəlidir:

kotlin
suspend fun loadUserProfile(id: String): Profile {
    return withContext(Dispatchers.IO) {
        val user = api.fetchUser(id)
        val posts = api.fetchPosts(id)
        Profile(user, posts)
    }
}

Hər iki əməliyyat Dispatchers.IO-da icra olunur və Profile nəticəsi lazımsız kontekst dəyişikliyi olmadan yaradılıb qaytarılır. Əməliyyatlar müstəqildirsə, paralel icra üçün async istifadə etmək daha yaxşıdır.

Nümunə 3: NonCancellable ilə qarışıq kontekst

Bəzi ssenarilərdə ləğv edilə bilməyən kodu icra etmək lazımdır — məsələn, ekran bağlanarkən vəziyyətin saxlanması. withContext + NonCancellable kombinasiyası bu tapşırığı həll edir:

kotlin
withContext(Dispatchers.IO + NonCancellable) {
    cache.saveState(state)
    analytics.logEvent("state_saved")
}

+ operatoru iki kontekst elementini birləşdirir: IO dispatcher-i və NonCancellable bayrağı. Blok ana korutina ləğv edilsə belə icra olunur — bu, yekunlaşdırma əməliyyatları üçün faydalıdır.

Daxili mexanizm: Continuation və optimallaşdırmalar

withContext-in daxili tətbiqi Continuation mexanizminə — Kotlin korutinalarının mərkəzi abstraksiyasına əsaslanır. Hər bir dayandırma nöqtəsi (suspend point) icra vəziyyətini Continuation obyektində saxlayır və withContext istisna deyil.

withContext bayt kod səviyyəsində konteksti necə dəyişir

Kotlin kompilyatoru withContext-i kotlinx.coroutines-dən withContext metoduna çağırış kimi tərcümə edir, o da daxildə yeni DispatchedContinuation nüsxəsi yaradır. Bu obyekt orijinal Continuation-ı bükür və orada dispatcher-i əvəz edir. Yeni dispatcher cari olandan fərqlidirsə, icra dayandırılır, blok müvafiq thread hovuzuna göndərilir və tamamlandıqdan sonra orijinal kontekstlə bərpa olunur.

Optimallaşdırma: kontekstlər uyğun gələndə fast-path

withContext korutinanın artıq işlədiyi eyni dispatcher ilə çağırıldıqda, Kotlin fast-path işə salır: blok sinxron şəkildə, DispatchedContinuation yaratmadan və thread hovuzuna ötürmədən icra olunur. Bu, withContext-i eyni kontekstlə təkrar çağırışlarda praktiki olaraq pulsuz edir. JetBrains benchmarklarına görə (kotlinx.coroutines 1.8), fast-path 0.1 μs-dən az müddətdə icra olunur.

Məhsuldarlıq baxımından məhdudiyyətlər

Fərqli dispatcher ilə hər withContext çağırışı yeni DispatchedContinuation yaradır və thread dəyişməsi tələb edir — bu, yükdən asılı olaraq 1-dən 5 μs-ə qədər vaxt aparır. Əksər tətbiqlər üçün bu gecikmə nəzərə çarpmır, lakin minlərlə iterasiyası olan dövrülərdə əməliyyatları bir withContext blokunda toplamaq daha yaxşıdır.

withContext istifadəsində tipik səhvlər

Hətta təcrübəli tərtibatçılar withContext ilə işləyərkən səhv edirlər. Dörd ən çox yayılmış problemi və onların qarşısını almaq yollarını nəzərdən keçirək.

Səhv 1: Lazımsız iç-içə withContext

Tərtibatçılar tez-tez hər sətri ayrıca withContext-ə yerləşdirir, əməliyyatları bir blokda birləşdirmək əvəzinə. Fərqli dispatcher ilə hər əlavə çağırış əlavə yük yaradır.

Düzgün: ardıcıl IO əməliyyatlarını bir withContext(Dispatchers.IO) { ... } blokunda birləşdirin. Əgər əməliyyatların bir hissəsi CPU intensivdirsə — eyni blok daxilində withContext(Dispatchers.Default) istifadə edin.

Səhv 2: Paralel tapşırıqlar üçün withContext-in əvəzinə istifadəsi

withContext kodu ardıcıl icra edir. İki müstəqil şəbəkə sorğusu bir withContext-ə yerləşdirilirsə, onlar bir-birinin ardınca icra olunacaq. Paralellik üçün async + await istifadə edin.

kotlin
// Ardıcıl — yavaş
withContext(Dispatchers.IO) {
    val a = api.fetchA()
    val b = api.fetchB()
}

// Paralel — sürətli
coroutineScope {
    val a = async { api.fetchA() }
    val b = async { api.fetchB() }
    println("${a.await()} ${b.await()}")
}

Səhv 3: Kritik əməliyyatlarda NonCancellable-ı unutmaq

Korutina withContext zamanı ləğv edilərsə, Dispatchers.IO-dakı blok da kəsilir. Nəyin bahasına olursa olsun tamamlanmalı olan əməliyyatlar üçün (verilənlər bazasına yazma, analitika göndərmə) withContext-i NonCancellable ilə birləşdirin.

Səhv 4: IO bloku daxilində UI vəziyyətinin dəyişdirilməsi

Heç vaxt View komponentlərini withContext(Dispatchers.IO) daxilində yeniləməyin. withContext bütün blok tamamlanana qədər Main-ə qayıtmır. UI yeniləməsini withContext-in bağlanan mötərizəsindən sonra edin — onda korutina artıq əsas thread-də olacaq.

Tez-tez verilən suallar

withContext runBlocking-dən nə ilə fərqlənir?

withContext — thread-i bloklamayan, mövcud korutina daxilində konteksti dəyişən dayandırıcı funksiyadır. runBlocking — korutinalar və adi kod arasında körpüdür, cari thread-i tamamlanana qədər bloklayır. withContext UI thread-i üçün təhlükəsizdir, runBlocking isə yox.

withContext-i suspend olmadan istifadə etmək olarmı?

Xeyr, withContext dayandırıcı funksiyadır, ona görə də onu yalnız başqa dayandırıcı funksiyadan və ya korutinadan (launch/async) çağırmaq olar. Adi funksiyadan withContext çağırılmır — bunun üçün runBlocking və ya CoroutineScope lazımdır.

withContext-ə eyni dispatcher-i versəm nə olar?

Kotlin fast-path aktivləşdirir — blok eyni thread-də sinxron şəkildə icra olunur, dəyişiklik olmadan. Əlavə yük 0.1 μs-dən azdır. Bu səhv deyil, lakin belə çağırış lazımsızdır — kodu sadəcə withContext olmadan icra etmək daha yaxşıdır.

withContext istisnalarla necə işləyir?

withContext daxilindəki istisnalar adi koddakı kimi — try-catch vasitəsilə ötürülür. Blok istisna atarsa, o, ana korutinaya yayılır və idarə edilməzsə onu ləğv edir. withContext daxilində və ya onun ətrafında try-catch istifadə edin.

withContext yeni korutina yaradırmı?

Xeyr, withContext yeni korutina yaratmır. O, mövcud korutinadan istifadə edir, lakin müvəqqəti olaraq onun kontekstini dəyişir. Bu, onu launch və async-dən fərqləndirir, çünki onlar uşaq korutinalar yaradır. Davranış kotlinx.coroutines mənbə kodu ilə təsdiqlənmişdir.

Xülasə

  • withContext — mövcud korutina daxilində CoroutineContext-i dəyişmək üçün dayandırıcı funksiyadır, avtomatik orijinal kontekstə qayıdır
  • Dispatchers.IO — withContext daxilində şəbəkə sorğuları və disk əməliyyatları üçün əsas dispatcher-dir
  • Fast-path — Kotlin optimallaşdırması, eyni dispatcher ilə withContext sinxron şəkildə əlavə yük olmadan icra olunur
  • Paralel tapşırıqlar async/await tələb edir, withContext deyil — withContext kodu ardıcıl icra edir
  • NonCancellable — korutina ləğv edildikdə kəsilməməli olan kritik əməliyyatlar üçün bayraqdır
  • Repository qatı — Google təlimatlarına görə Android arxitekturasında withContext üçün tövsiyə olunan yerdir
  • Continuation — Kotlin bayt kod səviyyəsində withContext-də kontekst dəyişməsinin əsasında duran mexanizmdir

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