Оптимізація потоків та конкурентності мобільного додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Оптимізація потоків та конкурентності мобільного додатку
Складний
~3-5 днів
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Оптимізація потоків та конкурентності мобільної програми

Deadlock у iOS-програмі відтворюється нестабільно: раз у 20–30 хвилин програма зависає. В crash-логах — нічого, тому що це не краш, це deadlock. Thread state dump через Xcode показує: main thread заблокований на DispatchQueue.sync до SerialQueue, а SerialQueue чекає completion handler, який намагається виконатися на main thread. Класичний deadlock двох потоків.

Конкурентність — одна з найскладніших тем у мобільній розробці. Гонки даних, дедлоки, UI-обновлення не з main thread — ці помилки появляються рідко, відтворюються нестабільно та дорого коштують у продакшені.

Типові проблеми з потоками

UI-обновлення не з main thread

На Android: CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. Причина — обробка мережевої відповіді напрямки в колбеку Retrofit без withContext(Dispatchers.Main).

На iOS: Main Thread Checker у Xcode (включений за умовчанням у Scheme settings) ловить обращення до UIKit з фонових потоків у debug-сборці. У релізі — випадкові краші або visual corruption.

Правильний паттерн iOS:

DispatchQueue.global(qos: .userInitiated).async {
    let result = heavyComputation()
    DispatchQueue.main.async {
        self.label.text = result // тільки тут
    }
}

Thread explosion з GCD

DispatchQueue.global().async створює новий поток при кожному виклику, якщо всі worker threads зайняті. При 64+ одночасних async-завданнях система починає створювати потоки агресивно — це thread explosion. Симптом: все працює нормально, потім різка деградація продуктивності під навантаженням.

Рішення: обмежена concurrency через OperationQueue.maxConcurrentOperationCount або через Swift Concurrency TaskGroup з явним withTaskGroup та обмеженим паралелізмом:

await withTaskGroup(of: Result.self) { group in
    for item in items.prefix(4) { // не більше 4 паралельних завдань
        group.addTask { await process(item) }
    }
}

Data races

Кілька потоків читають та пишуть одне поле без синхронізації. На Swift — Thread Sanitizer (TSan) знаходить гонки даних у debug-сборці. Включається в Scheme → Diagnostics → Thread Sanitizer.

Варіанти синхронізації:

  • NSLock / os_unfair_lock — швидкі мьютекси для критичних секцій
  • DispatchQueue(label:attributes:.concurrent) з barrier для read-write lock паттерну
  • actor у Swift 5.5+ — найсучасніший спосіб, компілятор гарантує ізоляцію даних
actor UserCache {
    private var storage: [String: User] = [:]

    func get(_ id: String) -> User? { storage[id] }
    func set(_ user: User) { storage[user.id] = user }
}

З actor компілятор не позволить обратиться до storage поза actor-контекстом без await.

Android: неправильне використання Coroutines

GlobalScope.launch — червона прапорець. Coroutine живе нескінченно, не отменяется при закритті екрана. При повторному відкритті — створюється другий. Правильно — viewModelScope.launch (отменяется при onCleared) або lifecycleScope.launch (отменяется при onDestroy).

Dispatchers.Main vs Dispatchers.Main.immediate: при виклику з main thread Dispatchers.Main.immediate виконується синхронно без переключення контексту — важливо для анімацій та негайних UI-обновлень.

Неправильна обробка винятків у coroutines:

// НЕПРАВИЛЬНО — виняток не буде перехвачено
scope.launch {
    try { riskyOperation() } catch (e: Exception) { handle(e) }
}

// ПРАВИЛЬНО — CoroutineExceptionHandler для структурної обробки
val handler = CoroutineExceptionHandler { _, e -> handleError(e) }
scope.launch(handler) { riskyOperation() }

Інструменти діагностики

Інструмент Платформа Що знаходить
Thread Sanitizer (TSan) iOS / Android Data races
Main Thread Checker iOS UI з фонового потоку
Instruments → Time Profiler iOS Заблоковані потоки
Android Studio Profiler → Threads Android Стани потоків, sleep/block/run
StrictMode Android Disk/network на main thread
Kotlin Coroutines Debugger Android Активні coroutines, їх стеки

StrictMode на Android — включаємо у debug-сборці:

StrictMode.setThreadPolicy(
    StrictMode.ThreadPolicy.Builder()
        .detectDiskReads().detectNetworkOnMainThread()
        .penaltyLog().penaltyFlashScreen()
        .build()
)

Мигання екрана при порушенні — неможливо ігнорувати.

Випадок: deadlock у Swift

E-commerce програма: при додаванні в кошик UI іноді зависав на 30–60 секунд. Відтворювалось лише при поганому інтернеті.

Через Thread State dump вияснилось: CartService.addItem() викликав userDefaults.synchronize() всередині serialQueue.sync, а synchronize() всередині чекав NSFileCoordinator, який теж стояв у черзі на запис. При мережевій затримці кілька викликів addItem() вишиковувались та один із них потрапляв у deadlock з NSFileCoordinator.

Рішення: видалили synchronize() (no-op у iOS 12+), перевели збереження кошика на async запис через DispatchQueue.global().async.

Етапи роботи

  1. Включаємо TSan та Main Thread Checker на всіх прогонах тестів
  2. Аналізуємо Thread state у Instruments / Android Profiler Threads view
  3. Перевіряємо всі місця з sync викликами та shared mutable state
  4. Виправляємо: weak references, правильні dispatch queues, actor isolation
  5. Навантажувальне тестування для виявлення race conditions під навантаженням

Часові рамки

Аудит конкурентності — 2–4 дні. Виправлення знайдених проблем — 3–14 днів залежно від глибини архітектурних рішень.