Mobil ishlanmada Ko'p oqimlilik va Konkurentlik: bu nima, tamoyillari va qanday ishlaydi

Muallif: IT Sectr Nashr etilgan: 2026-03-12 O'qish vaqti: 13 daq

Har bir mobil ilova bir vaqtning o'zida ko'plab vazifalarni bajaradi: tarmoqdan ma'lumot yuklaydi, foydalanuvchi teginishlarini qayta ishlaydi, interfeysni animatsiya qiladi va fayllarni saqlaydi. Agar bu kodning hammasi bitta oqimda ishlasa, ilova har qanday tarmoq kechikishida muzlab qoladi. Ko'p oqimlilik (multithreading) va konkurentlik ilovaning sezgir va samarali bo'lib qolishiga imkon beradigan asosiy tushunchalardir. Ushbu maqolada biz barcha asosiy vositalarni ko'rib chiqamiz: Main Thread va RunLoop-dan Kotlin korutinlarigacha va iOS-da Combine. Material Apple rasmiy GCD hujjatlariga asoslangan.

Asosiy Fikrlar

  • Main Thread — UI bilan ishlash uchun yagona oqim; qolgan barcha vazifalar Background-ga o'tkaziladi
  • GCD va OperationQueue — iOS-da ko'p oqimlilikning asosiy mexanizmlari
  • Coroutines va Flow — Kotlin/Android-da asinxronlikning zamonaviy standarti
  • RxJava, RxSwift va Combine — ma'lumot oqimlari bilan ishlash uchun reaktiv freymvorklar
  • Race Condition, Deadlock va Livelock — sinxronizatsiyani talab qiladigan klassik ko'p oqimlilik muammolari
  • Vositani tanlash platforma va vazifa murakkabligiga bog'liq: oddiy chaqiruvlar uchun Async/Await yetarli, murakkab oqimlar uchun — Rx yoki Combine

Ko'p oqimlilik nima?

Ko'p oqimlilik — bu ilovaning bir vaqtning o'zida bir nechta kod qismlarini bajarish qobiliyatidir. Har bir qism alohida oqimda (Thread) bajariladi — o'z chaqiruv stekiga ega engil jarayon. Mobil ishlanmada oqimlar ikki toifaga bo'linadi: Main Thread (UI oqimi) va Background Threads (fon oqimlari).

Operatsion tizim o'zi oqimlarni protsessor yadrolari bo'ylab taqsimlashni boshqaradi. Zamonaviy qurilmalarda 6–8 yadro mavjud, shuning uchun parallel bajarish ishni tezlashtirishi mumkin. Biroq, oqim yaratish qimmat operatsiya, shuning uchun to'g'ridan-to'g'ri Thread bilan ishlash tavsiya etilmaydi. Buning o'rniga yuqori darajadagi abstraksiyalar ishlatiladi: DispatchQueue, OperationQueue, CoroutineDispatcher.

Konkurentlik (Concurrency) ko'p oqimlilikdan kengroq tushunchadir. Konkurentlik kontekstni almashtirish orqali hatto bitta yadroda ham vazifalarni "bir vaqtning o'zida" bajarish mumkinligini anglatadi. Asinxronlik (Async/Await) — bu vazifa oqimni bloklamaydigan, natijani kutish paytida boshqaruvni qaytaradigan dasturlash modelidir. Zamonaviy tillar (Kotlin, Swift, Dart) Async/Await uchun o'rnatilgan qo'llab-quvvatlashga ega.

IT Sectr-da biz loyiha boshida to'g'ri ko'p oqimlilik arxitekturasiga alohida e'tibor beramiz. Dastlabki bosqichda qilingan xatolar ushlash qiyin bo'lgan xatolarga olib keladi: ma'lumot poygalari, o'zaro blokirovkalar va yuk ostida ilovaning beqarorligi. Har bir loyihamiz rejalashtirish bosqichida konkurentlik arxitektura ko'rib chiqishidan o'tadi.

Asosiy oqimlar (Main/Background)

Main Thread (asosiy oqim) — mobil ilovada UI-ga kirish imkoniyatiga ega bo'lgan yagona oqim. Android-da u UI Thread deb ataladi, iOS-da — Main Thread. Barcha interfeys operatsiyalari — matnni o'zgartirish, animatsiya, teginishlarni qayta ishlash — faqat Main Thread-da bajariladi. Agar asosiy oqimda og'ir operatsiya (fayl yuklash, JSON tahlil qilish) bajarilsa, interfeys javob berishni to'xtatadi. Android-da bu ANR (Application Not Responding) ga, iOS-da — ekranning "muzlashiga" olib keladi.

Background Threads (fon oqimlari) UI bilan bog'liq bo'lmagan hamma narsa uchun mo'ljallangan: tarmoq so'rovlari, ma'lumotlar bazasi operatsiyalari, tasvirni qayta ishlash, kriptografiya. Tugagandan so'ng, natija ko'rsatish uchun Main Thread-ga uzatiladi. Har bir platforma oqimlar o'rtasida almashish uchun o'z vositalarini taqdim etadi: iOS-da DispatchQueue.main.async, Android-da runOnUiThread yoki withContext(Dispatchers.Main).

RunLoop — iOS asosiy oqimidagi hodisalarni qayta ishlash siklidir. RunLoop hodisalarni (teginishlar, taymerlar, bildirishnomalar) kutadi va ularni tegishli ishlovchilarga yo'naltiradi. Android-da ekvivalent har bir Main Thread bilan bog'langan Looper dir. Main Looper navbatdan cheksiz ravishda xabarlarni chiqaradi va qayta ishlash uchun Handler-ga uzatadi. RunLoop va Looper-ni tushunish xotira oqishlari va interfeys "qoqilishlari" dan qochishga yordam beradi.

GCD va OperationQueue (iOS)

Grand Central Dispatch (GCD) — C tili darajasida ko'p oqimlilikni boshqarish uchun Apple kutubxonasi. GCD DispatchQueue — vazifalar navbatlari bilan ishlaydi. Dasturchi qo'lda oqim yaratmaydi; GCD mavjud protsessor yadrolari bo'ylab vazifalarni taqsimlab, oqim hovuzini (Thread Pool) boshqaradi. DispatchQueue ikki xil bo'ladi: Serial Queue (ketma-ket navbat — vazifalar birin-ketin bajariladi) va Concurrent Queue (parallel navbat — vazifalar bir vaqtda bajarilishi mumkin).

Main DispatchQueue — asosiy oqimga bog'langan ketma-ket navbat. Global Queues — turli ustuvorliklarga ega (QoS — Quality of Service) parallel navbatlar: userInteractive, userInitiated, utility, background. To'g'ri QoS ni tanlash ishlash uchun juda muhim: .userInteractive — UI ga ta'sir qiluvchi vazifalar uchun (animatsiyalar, renderlash); .background — vaqtga sezgir bo'lmagan vazifalar uchun (sinxronizatsiya, keshni tozalash).

OperationQueue — qo'shimcha imkoniyatlarga ega GCD ustidagi abstraksiya: vazifalarni bekor qilish, operatsiyalar o'rtasida bog'liqliklarni o'rnatish, parallel operatsiyalarning maksimal sonini nazorat qilish. Operatsiyalar Operation sinfining (yoki BlockOperation) ob'ektlaridir. Misol: rasmni yuklash, keyin filtrni qo'llash va faqat keyin uni ko'rsatish kerak bo'lsa — bog'liqliklarga ega OperationQueue buni mukammal boshqaradi. GCD-da siz DispatchGroup yoki semafor yordamida bu qadamlarni qo'lda sinxronlashtirishingiz kerak bo'ladi.

Swift 5.5+ da Async/Await — GCD ga zamonaviy muqobildir. async va await kalit so'zlari asinxron kodni chiziqli va o'qilishi oson qiladi. Funksiyalar async deb belgilanadi va chaqiruvlar await orqali kutiladi. Tizim o'zi kontekstni almashtirishni boshqaradi: standart bo'yicha async funksiyasi fon oqimida bajariladi, UI yangilanishi esa MainActor da bajariladi. @MainActor — kodning asosiy oqimda bajarilishini kafolatlaydigan atribut.

Coroutines va Flow (Kotlin)

Coroutines (korutinlar) — JetBrains tomonidan ishlab chiqilgan Kotlin uchun engil oqimlardir. Oddiy oqimlardan farqli o'laroq, korutinlar ma'lum bir Thread ga bog'liq emas. Minglab korutinlar sezilarli yuksiz bir nechta oqimlarda ishlashi mumkin. CoroutineScope korutinlarning hayotiy siklini boshqaradi: viewModelScope ViewModel ga bog'langan, lifecycleScope — Activity/Fragment ga. Ko'lam yo'q qilinganda, barcha bolali korutinlar avtomatik ravishda bekor qilinadi.

Dispatchers korutin qaysi oqim hovuzida bajarilishini aniqlaydi: Dispatchers.Main — UI oqimi; Dispatchers.IO — tarmoq so'rovlari va disk operatsiyalari uchun; Dispatchers.Default — CPU sig'imli hisob-kitoblar uchun. Dispetcherni o'zgartirish uchun withContext ishlatiladi. Korutinlar tuzilgan konkurentlikni (structured concurrency) qo'llab-quvvatlaydi: har bir korutinning ota-onasi bor va ota-ona bekor qilinganda barcha bolali korutinlar bekor qilinadi. Bu xotira oqishlari va osilgan vazifalarni oldini oladi.

Flow — korutinlar kutubxonasidan sovuq asinxron ma'lumot oqimi. Flow qiymatlarni ketma-ket chiqaradi: (1) ishlab chiqaruvchi ma'lumot yaratadi, (2) operatorlar oqimni o'zgartiradi, (3) yig'uvchi natijani iste'mol qiladi. LiveData dan farqli o'laroq, Flow murakkab operator zanjirlarini (map, filter, flatMapConcat, catch) qo'llab-quvvatlaydi va butunlay oqim xavfsizdir. StateFlow va SharedFlow — Flow ning issiq turlari, UI holati va bir martalik hodisalar (Snackbar, navigatsiya) uchun ideal.

Channel — korutinlar o'rtasida ma'lumot uzatish uchun yana bir korutin abstraksiyasi. Channel navbat kabi ishlaydi: bitta jo'natuvchi (send) va bir yoki bir nechta qabul qiluvchi (receive). Buferlangan kanallar (Channel(UNLIMITED), Channel(BUFFERED)) toshib ketishda xatti-harakatni sozlash imkonini beradi. Channel ko'pincha Flow bilan birga callback-ga asoslangan API larni korutinlarga ulash uchun ishlatiladi: callbackFlow { … }.

IT Sectr da biz barcha Android loyihalarida korutinlar va Flow dan faol foydalanamiz. Bu sinxron ko'rinadigan asinxron kod yozish, oson sinab ko'rish (runTest, TestDispatcher) va qo'lda oqim boshqaruvini talab qilmaydi. Ma'lumot yuklash bilan oddiy korutin namunasi:

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 va Combine

Reaktiv dasturlash — ma'lumotlar asinxron oqimlar (Observable, Publisher) sifatida tarqaladigan paradigmadir. RxJava/RxKotlin — Android uchun eng mashhur tatbiq, .NET Rx dan ko'chirilgan. RxSwift — iOS uchun o'xshash kutubxona. Asosiy komponentlar: Observable (hodisa manbai), Observer (obunachi), Scheduler (oqim boshqaruvi), Operators (oqim transformatsiyasi).

Combine — iOS 13 da taqdim etilgan Apple reaktiv dasturlash freymvorki. Combine Publisher (nashriyotchi) va Subscriber (obunachi) protokollaridan foydalanadi. RxSwift dan farqli o'laroq, Combine SDK ga o'rnatilgan va SwiftUI bilan chambarchas integratsiyalangan. Combine dagi operatorlar: map, filter, combineLatest, zip, debounce, throttle — ma'lumot bog'lashdan tortib qidiruv so'rovini debaunsingacha bo'lgan ko'pchilik stsenariylarni qamrab oladi.

Future va Promise — yagona asinxron natija bilan ishlash uchun namunalar. Future keyinroq mavjud bo'ladigan qiymatni ifodalaydi. Promise qiymatni taqdim etish va'dasidir. Rx da bu Single (bitta muvaffaqiyatli javob yoki xato), Combine da — Future Publisher. Amalda, Future/Promise yagona API so'rovlari uchun qulay, Observable/Publisher esa uzluksiz oqimlar (geolokatsiya, matn kiritish) uchun qulay.

Callback va Delegate — asinxron operatsiyalar uchun klassik namunalar. Callback — argument sifatida uzatiladigan va operatsiya tugagandan so'ng chaqiriladigan funksiya. Delegate — hodisa ishlovchi usullari bilan protokolni amalga oshiradigan ob'ekt. Kamchilik: "callback do'zaxi" (ichma-ich callbacklar) va xatolarni qayta ishlash murakkabligi. NotificationCenter (iOS) va EventBus (Android) — hodisa eshittirish mexanizmlari, zaif bog'langan aloqa uchun foydali, ammo yashirin bog'liqliklarga olib keladi.

Ko'p oqimlilik muammolari (Race Condition, Deadlock)

Ko'p oqimlilik yuqori samaradorlik eshigini ochadi, lekin bir vaqtning o'zida ushlash qiyin bo'lgan xatolar xavfini yaratadi. Eng keng tarqalganlari: Race Condition (poyga holati), Deadlock (o'zaro blokirovka), Livelock (faol blokirovka) va Starvation (oqim ochligi). Bu muammolarni tushunish har qanday mobil dasturchi uchun majburiy mahoratdir.

Race Condition

Race Condition ikki yoki undan ortiq oqim sinxronizatsiyasiz bir vaqtning o'zida bir xil ma'lumotlarni o'qigan va yozganda yuzaga keladi. Natija qaysi oqim birinchi bajarilishiga bog'liq. Klassik misol: ikki oqim hisoblagichni oshiradi. "O'qi → oshir → yoz" operatsiyasi atomik emas, shuning uchun bir vaqtda bajarilganda bitta oshirish "yo'qoladi". Yechim — atomik operatsiyalar (AtomicInteger, AtomicReference) yoki qulflardan (Mutex, Semaphore, synchronized) foydalanish.

Deadlock

Deadlock — har bir oqim resursni ushlab turadigan va boshqa oqim tomonidan egallab olingan resursni kutadigan vaziyat. Hech bir oqim davom eta olmaydi. Yuzaga kelish shartlari: o'zaro istisno, ushlab turish va kutish, oldindan olish yo'q, tsiklik kutish. Oldini olish: qulf olishning yagona tartibini o'rnatish, vaqt chegarasi bilan tryLock dan foydalanish, Lock-Free algoritmlarini (ConcurrentHashMap, CopyOnWriteArrayList) qo'llash.

Livelock va Starvation

Livelock — oqimlar bloklanmagan, lekin foydali ish qilmasdan doimiy ravishda bir-biriga resurslarni "uzatadi". Misol: ikki kishi koridorda uchrashadi va ikkalasi ham bir xil yo'nalishda harakatlanib yo'l beradi. Starvation — oqim resursga kirish ololmaydi, chunki boshqa oqimlar uni doimiy ravishda tutib oladi. Yechim: adolatli qulflar (fair locks), ehtiyotkorlik bilan oqim ustuvorliklari.

Sinxronizatsiya vositalari

Ko'p oqimlilik muammolarini oldini olish uchun sinxronizatsiya primitivlaridan foydalaniladi: Mutex (o'zaro istisno), Semaphore (bir vaqtda kirishlar sonini cheklash), Lock (tryLock bilan interfeys), Synchronized (JVM darajasidagi qulf), @MainActor (Swift — asosiy oqimda bajarilish kafolati). Android da Executors.newFixedThreadPool, newCachedThreadPool orqali ThreadPool ham mavjud. Biroq, qo'lda hovuz boshqaruvi eski loyihalarning imtiyozi; yangi loyihalarda korutinlardan foydalanish yaxshiroq.

Vosita Platforma Tur Xususiyatlar
DispatchQueue (GCD)iOSVazifa navbatiKetma-ket/Parallel, QoS ustuvorliklari, Thread Pool tizim tomonidan boshqariladi
OperationQueueiOSOperatsiya navbatiBog'liqliklar, bekor qilish, maxConcurrentOperationCount
Coroutines + FlowAndroidKorutinlarYengil, tuzilgan konkurentlik, StateFlow, Channel
RxJava / RxKotlinAndroidReaktiv oqimObservable, Schedulers, boy operatorlar to'plami
CombineiOSReaktiv oqimPublisher/Subscriber, SwiftUI integratsiyasi
Async/Await + TaskiOS / AndroidAsinxron modelChiziqli kod, @MainActor, tuzilgan konkurentlik

Tez-tez beriladigan savollar

Main Thread va Background Thread o'rtasidagi farq nima?

Main Thread (UI oqimi) interfeysni renderlash va teginishlarni qayta ishlash uchun javobgardir. Background Thread fon vazifalarini bajaradi — ma'lumot yuklash, hisob-kitoblar, tarmoq ishi. Main Thread ni bloklash interfeys muzlashiga olib keladi (Android da ANR, iOS da frozen UI).

Race Condition nima va undan qanday qochish kerak?

Race Condition — ikki oqim bir vaqtning o'zida umumiy ma'lumotlarga kirishganda va natija bajarilish tartibiga bog'liq bo'lganda yuzaga keladigan poyga holati. Sinxronizatsiya orqali oldini olinadi: Mutex, Semaphore, Lock, Synchronized, @MainActor yoki atomik operatsiyalar.

Coroutines yoki RxJava: Android uchun qaysi birini tanlash kerak?

Coroutines Android uchun zamonaviy standartdir (JetBrains, Google tomonidan qo'llab-quvvatlanadi). RxJava/RxKotlin boy operatorlar to'plamiga ega reaktiv yondashuvdir. Coroutines asinxron chaqiruvlar uchun soddaroq, RxJava murakkab ma'lumot oqimlari uchun kuchliroq. IT Sectr da yangi loyihalar uchun Coroutines + Flow dan foydalanamiz.

Deadlock va Livelock nima?

Deadlock — ikki oqim bir-birining resurslarini kutadigan o'zaro blokirovka. Livelock — oqimlar bloklanmagan, lekin foydali ish qilmasdan doimiy ravishda resurslarni uzatadi. Ikkala muammo to'g'ri qulf tartibi va vaqt chegaralari bilan hal qilinadi.

iOS da DispatchQueue nima uchun kerak?

DispatchQueue oqim boshqaruvi uchun Grand Central Dispatch (GCD) ning abstraksiyasidir. Main Queue vazifalarni asosiy oqimda bajaradi, Global Queues — fon oqimlarida. Serial Queue ketma-ket bajarishni kafolatlaydi, Concurrent Queue — parallel. Zamonaviy loyihalarda GCD ko'pincha Async/Await va Task bilan almashtiriladi.

Xulosa

  • Main Thread — faqat UI; qolgan barcha operatsiyalar Background da
  • GCD va OperationQueue — iOS da ko'p oqimlilik asosi; Async/Await — zamonaviy muqobil
  • Coroutines va Flow — Android standarti; tuzilgan konkurentlik oqishlarni oldini oladi
  • RxJava, RxSwift, Combine — murakkab ma'lumot oqimlari uchun reaktiv freymvorklar
  • Race Condition va Deadlock — asosiy muammolar; qulflar va to'g'ri resurs olish tartibi bilan hal qilinadi
  • Thread Pool tizim (GCD) yoki freymvork (korutin) tomonidan boshqariladi; qo'lda oqim yaratish tavsiya etilmaydi
  • Vositani tanlash platformaga bog'liq: Android uchun Coroutines, iOS uchun GCD/Combine

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish