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

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
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

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

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() (в iOS 12+ он no-op), перевели сохранение корзины на 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 дней в зависимости от глубины архитектурных решений.