Mobil İnkişafda Çoxşaxəli və Eynivaxtlılıq: bu nədir, prinsipləri və necə işləyir

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

Hər mobil tətbiq eyni anda çoxlu tapşırıqları yerinə yetirir: şəbəkədən məlumat yükləyir, istifadəçi toxunuşlarını emal edir, interfeysi animasiya edir və faylları saxlayır. Əgər bütün bu kod bir şaxədə işləyirsə, tətbiq hər hansı şəbəkə gecikməsində donur. Çoxşaxəli (multithreading) və eynivaxtlılıq tətbiqin cavabdeh və səmərəli qalmasını təmin edən əsas anlayışlardır. Bu məqalədə bütün əsas alətləri nəzərdən keçirəcəyik: Main Thread və RunLoop-dan Kotlin korutinlərinə və iOS-da Combine-a qədər. Material Apple-ın rəsmi GCD sənədlərinə əsaslanır.

Əsas Məqamlar

  • Main Thread — UI ilə işləmək üçün yeganə şaxə; bütün digər tapşırıqlar Background-a köçürülür
  • GCD və OperationQueue — iOS-da çoxşaxəliyin əsas mexanizmləri
  • Coroutines və Flow — Kotlin/Android-də asinxronluğun müasir standartı
  • RxJava, RxSwift və Combine — məlumat axınları ilə işləmək üçün reaktiv freymvorklar
  • Race Condition, Deadlock və Livelock — sinxronizasiya tələb edən klassik çoxşaxəli problemləri
  • Alət seçimi platformadan və tapşırığın mürəkkəbliyindən asılıdır: sadə çağırışlar üçün Async/Await kifayətdir, mürəkkəb axınlar üçün — Rx və ya Combine

Çoxşaxəli nədir?

Çoxşaxəli tətbiqin eyni anda bir neçə kod parçasını yerinə yetirmə qabiliyyətidir. Hər parça ayrı bir şaxədə (Thread) icra olunur — öz çağırış yığını olan yüngül proses. Mobil inkişafda şaxələr iki kateqoriyaya bölünür: Main Thread (UI şaxəsi) və Background Threads (fon şaxələri).

Əməliyyat sistemi özü şaxələrin prosessor nüvələri arasında paylanmasını idarə edir. Müasir cihazlarda 6–8 nüvə var, buna görə paralel icra işi sürətləndirə bilər. Bununla belə, şaxə yaratmaq bahalı əməliyyatdır, buna görə birbaşa Thread ilə işləmək tövsiyə edilmir. Bunun əvəzinə daha yüksək səviyyəli abstraksiyalardan istifadə olunur: DispatchQueue, OperationQueue, CoroutineDispatcher.

Eynivaxtlılıq (Concurrency) çoxşaxəlidən daha geniş anlayışdır. Eynivaxtlılıq o deməkdir ki, tapşırıqlar kontekst dəyişməsi vasitəsilə hətta bir nüvədə də "eyni anda" icra oluna bilər. Asinxronluq (Async/Await) — tapşırığın şaxəni bloklamadığı, nəticə gözlənilərkən nəzarəti qaytardığı proqramlaşdırma modelidir. Müasir dillər (Kotlin, Swift, Dart) daxili Async/Await dəstəyinə malikdir.

IT Sectr-də layihənin başlanğıcında düzgün çoxşaxəli arxitekturasına xüsusi diqqət yetiririk. Erkən mərhələdə buraxılan səhvlər tutulması çətin olan səhvlərə gətirib çıxarır: məlumat yarışları, qarşılıqlı bloklamalar və yük altında tətbiqin qeyri-sabitliyi. Hər layihəmiz planlaşdırma mərhələsində eynivaxtlılıq arxitektura icmalından keçir.

Əsas şaxələr (Main/Background)

Main Thread (əsas şaxə) — mobil tətbiqdə UI-ya çıxışı olan yeganə şaxədir. Android-də buna UI Thread deyilir, iOS-da — Main Thread. Bütün interfeys əməliyyatları — mətn dəyişdirmə, animasiya, toxunuş emalı — yalnız Main Thread-də yerinə yetirilir. Əsas şaxədə ağır əməliyyat (fayl yükləmə, JSON təhlili) icra olunarsa, interfeys cavab verməyi dayandırır. Android-də bu ANR (Application Not Responding)-ə, iOS-da — ekranın "donmasına" səbəb olur.

Background Threads (fon şaxələri) UI ilə əlaqəli olmayan hər şey üçün nəzərdə tutulub: şəbəkə sorğuları, verilənlər bazası əməliyyatları, təsvir emalı, kriptoqrafiya. Tamamlandıqdan sonra nəticə göstərilmək üçün Main Thread-ə ötürülür. Hər platforma şaxələr arasında keçid etmək üçün öz alətlərini təqdim edir: iOS-da DispatchQueue.main.async, Android-də runOnUiThread və ya withContext(Dispatchers.Main).

RunLoop — iOS əsas şaxəsində hadisə emal dövrəsidir. RunLoop hadisələri (toxunuşlar, taymerlər, bildirişlər) gözləyir və onları müvafiq işləyicilərə çatdırır. Android-də ekvivalent hər Main Thread ilə əlaqəli Looper-dir. Main Looper növbədən sonsuz olaraq mesajları çıxarır və emal üçün Handler-ə ötürür. RunLoop və Looper-i başa düşmək yaddaş sızmalarından və interfeys "tutulmalarından" qaçmağa kömək edir.

GCD və OperationQueue (iOS)

Grand Central Dispatch (GCD) — C dili səviyyəsində çoxşaxəlini idarə etmək üçün Apple kitabxanasıdır. GCD DispatchQueue — tapşırıq növbələri ilə işləyir. Tərtibatçı əl ilə şaxə yaratmır; GCD mövcud prosessor nüvələri arasında tapşırıqları paylayaraq şaxə hovuzunu (Thread Pool) idarə edir. DispatchQueue iki növdür: Serial Queue (ardıcıl növbə — tapşırıqlar bir-birinin ardınca icra olunur) və Concurrent Queue (paralel növbə — tapşırıqlar eyni anda icra oluna bilər).

Main DispatchQueue — əsas şaxəyə bağlı ardıcıl növbədir. Global Queues — müxtəlif prioritetlərə (QoS — Quality of Service) malik paralel növbələrdir: userInteractive, userInitiated, utility, background. Düzgün QoS seçimi performans üçün kritikdir: .userInteractive — UI-ya təsir edən tapşırıqlar üçün (animasiyalar, renderinq); .background — zamana həssas olmayan tapşırıqlar üçün (sinxronizasiya, keş təmizləmə).

OperationQueue — əlavə imkanlarla GCD üzərində abstraksiyadır: tapşırıqları ləğv etmə, əməliyyatlar arasında asılılıqlar qurma, paralel əməliyyatların maksimum sayını idarə etmə. Əməliyyatlar Operation sinfinin (və ya BlockOperation) obyektləridir. Nümunə: şəkli yükləmək, sonra filtr tətbiq etmək və yalnız bundan sonra göstərmək lazımdırsa — asılılıqları olan OperationQueue bunu mükəmməl idarə edir. GCD-də bu addımları DispatchGroup və ya semafor vasitəsilə əl ilə sinxronizasiya etməli olardınız.

Swift 5.5+-da Async/Await — GCD-yə müasir alternativdir. asyncawait açar sözləri asinxron kodu xətti və oxunaqlı edir. Funksiyalar async olaraq işarələnir və çağırışlar await vasitəsilə gözlənilir. Sistem özü kontekst dəyişməsini idarə edir: standart olaraq async funksiyası fon şaxəsində icra olunur, UI yeniləməsi isə MainActor-da icra olunur. @MainActor — kodun əsas şaxədə icrasını təmin edən atributdur.

Coroutines və Flow (Kotlin)

Coroutines (korutinlər) — JetBrains tərəfindən hazırlanmış Kotlin üçün yüngül şaxələrdir. Adi şaxələrdən fərqli olaraq, korutinlər müəyyən bir Thread-ə bağlı deyil. Minlərlə korutin əhəmiyyətli yük olmadan bir neçə şaxədə işləyə bilər. CoroutineScope korutinlərin həyat dövrünü idarə edir: viewModelScope ViewModel-ə bağlıdır, lifecycleScope — Activity/Fragment-ə. Çərçivə məhv edildikdə, bütün alt korutinlər avtomatik olaraq ləğv edilir.

Dispatchers korutinin hansı şaxə hovuzunda işləyəcəyini müəyyən edir: Dispatchers.Main — UI şaxəsi; Dispatchers.IO — şəbəkə sorğuları və disk əməliyyatları üçün; Dispatchers.Default — CPU gərgin hesablamalar üçün. Dispatcher dəyişdirmək üçün withContext istifadə olunur. Korutinlər strukturlaşdırılmış eynivaxtlılığı (structured concurrency) dəstəkləyir: hər korutinin valideyni var və valideyn ləğv edildikdə bütün alt korutinlər ləğv edilir. Bu yaddaş sızmalarının və asılı qalan tapşırıqların qarşısını alır.

Flow — korutin kitabxanasından soyuq asinxron məlumat axınıdır. Flow dəyərləri ardıcıl olaraq yayır: (1) prodüser məlumat yaradır, (2) operatorlar axını çevirir, (3) kollektor nəticəni istehlak edir. LiveData-dan fərqli olaraq, Flow mürəkkəb operator zəncirlərini (map, filter, flatMapConcat, catch) dəstəkləyir və tamamilə şaxə təhlükəsizdir. StateFlowSharedFlow — Flow-un istiqamətli növləridir, UI vəziyyəti və birdəfəlik hadisələr (Snackbar, naviqasiya) üçün idealdır.

Channel — korutinlər arasında məlumat ötürmək üçün başqa bir korutin abstraksiyasıdır. Channel növbə kimi işləyir: bir göndərən (send) və bir və ya daha çox qəbul edən (receive). Buferləşdirilmiş kanallar (Channel(UNLIMITED), Channel(BUFFERED)) daşma zamanı davranışı konfiqurasiya etməyə imkan verir. Channel tez-tez geri çağırış əsaslı API-ləri korutinlərə bağlamaq üçün Flow ilə birlikdə istifadə olunur: callbackFlow { … }.

IT Sectr-də bütün Android layihələrində korutinlərdən və Flow-dan aktiv istifadə edirik. Bu sinxron görünən asinxron kod yazmağa, asanlıqla test etməyə (runTest, TestDispatcher) və əl ilə şaxə idarəçiliyi tələb etmir. Məlumat yükləməsi olan sadə bir korutin nümunəsi:

kotlin
class UserRepository(
    private val api: UserApi,
    private val dao: UserDao
) {
    suspend fun getUsers(): List<User> = withContext(Dispatchers.IO) {
        return@withContext try {
            val users = api.fetchUsers()
            dao.insertAll(users)
            users
        } catch (e: Exception) {
            dao.getAll()
        }
    }
}

Rx və Combine

Reaktiv proqramlaşdırma — məlumatların asinxron axınlar (Observable, Publisher) kimi yayıldığı paradigmadır. RxJava/RxKotlin — Android üçün ən populyar tətbiqdir, .NET Rx-dən port edilmişdir. RxSwift — iOS üçün oxşar kitabxanadır. Əsas komponentlər: Observable (hadisə mənbəyi), Observer (abunəçi), Scheduler (şaxə idarəçiliyi), Operators (axın çevrilməsi).

Combine — iOS 13-də təqdim edilmiş Apple-ın reaktiv proqramlaşdırma freymvorkudur. Combine Publisher (nəşriyyatçı) və Subscriber (abunəçi) protokollarından istifadə edir. RxSwift-dən fərqli olaraq, Combine SDK-ya daxildir və SwiftUI ilə sıx inteqrasiya edilmişdir. Combine-də operatorlar: map, filter, combineLatest, zip, debounce, throttle — məlumat bağlamasından UI-a və axtarış sorğusu debaunsinqinə qədər əksər ssenariləri əhatə edir.

Future və Promise — tək asinxron nəticə ilə işləmək üçün nümunələrdir. Future daha sonra əlçatan olacaq dəyəri təmsil edir. Promise dəyər təqdim etmək vədidir. Rx-də bu Single (bir uğurlu cavab və ya xəta), Combine-da — Future Publisher-dir. Təcrübədə Future/Promise tək API sorğuları üçün əlverişlidir, Observable/Publisher isə davamlı axınlar (geolokasiya, mətn daxiletmə) üçün əlverişlidir.

Callback və Delegate — asinxron əməliyyatlar üçün klassik nümunələrdir. Callback — arqument kimi ötürülən və əməliyyat tamamlandıqda çağırılan funksiyadır. Delegate — hadisə işləyici metodları olan protokolu tətbiq edən obyektdir. Çatışmazlıq: "callback cəhənnəmi" (iç-içə callback-lər) və xəta idarəetmə mürəkkəbliyi. NotificationCenter (iOS) və EventBus (Android) — boş bağlı kommunikasiya üçün faydalı, lakin gizli asılılıqlara səbəb olan yayım hadisə mexanizmləridir.

Çoxşaxəli problemləri (Race Condition, Deadlock)

Çoxşaxəli yüksək performansın qapısını açır, eyni zamanda tutulması çətin səhvlər riski yaradır. Ən çox yayılanlar: Race Condition (yarış vəziyyəti), Deadlock (qarşılıqlı bloklama), Livelock (aktiv bloklama) və Starvation (şaxə aclığı). Bu problemləri başa düşmək hər hansı mobil tərtibatçı üçün məcburi bacarıqdır.

Race Condition

Race Condition iki və ya daha çox şaxə sinxronizasiya olmadan eyni məlumatları eyni anda oxuyub yazdıqda yaranır. Nəticə hansı şaxənin əvvəl icra olunmasından asılıdır. Klassik nümunə: iki şaxə sayğacı artırır. "Oxu → artır → yaz" əməliyyatı atomik deyil, buna görə eyni anda icra edildikdə bir artım "itir". Həll yolu — atomik əməliyyatlar (AtomicInteger, AtomicReference) və ya kilidlərdən (Mutex, Semaphore, synchronized) istifadə etməkdir.

Deadlock

Deadlock — hər şaxənin bir resursu saxladığı və başqa şaxə tərəfindən tutulmuş resursu gözlədiyi vəziyyətdir. Heç bir şaxə davam edə bilməz. Yaranma şərtləri: qarşılıqlı istisna, saxlama və gözləmə, öncədən alma yox, dövri gözləmə. Qarşısını alma: vahid kilid alma sırası təyin etmək, vaxt aşımı ilə tryLock istifadə etmək, Lock-Free alqoritmləri (ConcurrentHashMap, CopyOnWriteArrayList) tətbiq etmək.

Livelock və Starvation

Livelock — şaxələr bloklanmayıb, lakin faydalı iş görmədən davamlı olaraq bir-birinə resursları "ötürür". Nümunə: iki nəfər dəhlizdə qarşılaşır və hər ikisi eyni istiqamətdə hərəkət edərək yol verir. Starvation — bir şaxə digər şaxələr onu daim ələ keçirdiyi üçün resursa çıxış əldə edə bilmir. Həll: ədalətli kilidlər (fair locks), ehtiyatla şaxə prioritetləri.

Sinxronizasiya alətləri

Çoxşaxəli problemlərin qarşısını almaq üçün sinxronizasiya primitivlərindən istifadə olunur: Mutex (qarşılıqlı istisna), Semaphore (eyni vaxtda giriş sayını məhdudlaşdırma), Lock (tryLock ilə interfeys), Synchronized (JVM səviyyəli kilid), @MainActor (Swift — əsas şaxədə icraya zəmanət). Android-də Executors.newFixedThreadPool, newCachedThreadPool vasitəsilə ThreadPool da mövcuddur. Bununla belə, əl ilə hovuz idarəçiliyi köhnə layihələrin səlahiyyətidir; yeni layihələrdə korutinlərdən istifadə etmək daha yaxşıdır.

Alət Platforma Növ Xüsusiyyətlər
DispatchQueue (GCD)iOSTapşırıq növbəsiArdıcıl/Paralel, QoS prioritetləri, Thread Pool sistem tərəfindən idarə olunur
OperationQueueiOSƏməliyyat növbəsiAsılılıqlar, ləğv, maxConcurrentOperationCount
Coroutines + FlowAndroidKorutinlərYüngül, strukturlaşdırılmış eynivaxtlılıq, StateFlow, Channel
RxJava / RxKotlinAndroidReaktiv axınObservable, Schedulers, zəngin operator dəsti
CombineiOSReaktiv axınPublisher/Subscriber, SwiftUI inteqrasiyası
Async/Await + TaskiOS / AndroidAsinxron modelXətti kod, @MainActor, strukturlaşdırılmış eynivaxtlılıq

Tez-tez verilən suallar

Main Thread Background Thread-dən nə ilə fərqlənir?

Main Thread (UI şaxəsi) interfeysin göstərilməsinə və toxunuşların emalına cavabdehdir. Background Thread fon tapşırıqlarını yerinə yetirir — məlumat yükləmə, hesablamalar, şəbəkə işi. Main Thread-i bloklamaq interfeysin donmasına səbəb olur (Android-də ANR, iOS-da frozen UI).

Race Condition nədir və ondan necə qaçınmaq olar?

Race Condition — iki şaxə eyni anda paylaşılan məlumatlara daxil olduqda və nəticə icra sırasından asılı olduqda yaranan yarış vəziyyətidir. Sinxronizasiya vasitəsilə qarşısı alınır: Mutex, Semaphore, Lock, Synchronized, @MainActor və ya atomik əməliyyatlar.

Coroutines yoxsa RxJava: Android üçün hansı seçilməlidir?

Coroutines Android üçün müasir standartdır (JetBrains, Google tərəfindən dəstəklənir). RxJava/RxKotlin zəngin operator dəsti ilə reaktiv bir yanaşmadır. Coroutines asinxron çağırışlar üçün daha sadədir, RxJava mürəkkəb məlumat axınları üçün daha güclüdür. IT Sectr-də yeni layihələr üçün Coroutines + Flow istifadə edirik.

Deadlock və Livelock nədir?

Deadlock — iki şaxənin bir-birinin resurslarını gözlədiyi qarşılıqlı bloklamadır. Livelock — şaxələr bloklanmayıb, lakin faydalı iş görmədən davamlı resursları ötürür. Hər iki problem düzgün kilid sırası və vaxt aşımları ilə həll olunur.

iOS-da DispatchQueue nə üçün lazımdır?

DispatchQueue şaxə idarəçiliyi üçün Grand Central Dispatch (GCD) abstraksiyasıdır. Main Queue tapşırıqları əsas şaxədə icra edir, Global Queues — fon şaxələrində. Serial Queue ardıcıl icranı təmin edir, Concurrent Queue — paralel. Müasir layihələrdə GCD tez-tez Async/Await və Task ilə əvəz olunur.

Xülasə

  • Main Thread — yalnız UI; bütün digər əməliyyatlar Background-da
  • GCD və OperationQueue — iOS-da çoxşaxəliyin əsası; Async/Await — müasir alternativ
  • Coroutines və Flow — Android standartı; strukturlaşdırılmış eynivaxtlılıq sızmaların qarşısını alır
  • RxJava, RxSwift, Combine — mürəkkəb məlumat axınları üçün reaktiv freymvorklar
  • Race Condition və Deadlock — əsas problemlər; kilidlər və düzgün resurs alma sırası ilə həll olunur
  • Thread Pool sistem (GCD) və ya freymvork (korutin) tərəfindən idarə olunur; əl ilə şaxə yaratmaq tövsiyə edilmir
  • Alət seçimi platformadan asılıdır: Android üçün Coroutines, iOS üçün GCD/Combine

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