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

В нашей практике **deadlock** в iOS-приложении воспроизводился нестабильно: раз в 20–30 минут приложение зависало намертво. В crash-логах — ничего, потому что это не краш, а deadlock. Thread state dump через Xcode показывал: main thread заблокирован на `DispatchQueue.sync` в очередь `SerialQueue`, а

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

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

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

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

В нашей практике deadlock в iOS-приложении воспроизводился нестабильно: раз в 20–30 минут приложение зависало намертво. В crash-логах — ничего, потому что это не краш, а deadlock. Thread state dump через Xcode показывал: main thread заблокирован на DispatchQueue.sync в очередь SerialQueue, а SerialQueue ждёт completion handler, который пытается выполниться на main thread. Классический deadlock двух потоков. Такие ошибки конкурентности — одни из самых дорогих в мобильной разработке: они редкие, нестабильно воспроизводятся и часто проходят в прод. За 5 лет мы проанализировали более 50 проектов с подобными проблемами. Экономия времени на отладку конкурентности может достигать 60%, а экономия бюджета — до 30% за счёт снижения количества инцидентов.

Конкурентность — сложнейшая тема. Гонки данных, дедлоки, UI-обновления не с main thread — эти ошибки появляются редко и дорого стоят. Мы используем современные инструменты: Swift Concurrency, Kotlin Coroutines, Thread Sanitizer, чтобы исключить их на стадии разработки. Structured concurrency (async/await) в 3 раза повышает читаемость кода и в 2 раза снижает вероятность гонок по сравнению с GCD.

Как диагностика потоков помогает оптимизировать конкурентность?

Типичные симптомы: UI зависает на несколько секунд или навсегда, приложение не реагирует на касания. В отличие от краша, deadlock не генерирует crash-лог (в 40% случаев первым симптомом становится жалоба пользователя). Диагностика требует специальных инструментов. На iOS — Thread Sanitizer (TSan) в Xcode: он выявляет data races, но не все deadlock. В документации Apple указано: Thread Sanitizer выявляет гонки данных во время выполнения. Для deadlock используем Instruments → Time Profiler: смотрим, какие потоки заблокированы и на каких очередях. На Android — Android Studio Profiler → Threads: видим состояние RUNNABLE, WAIT, BLOCKED. StrictMode ловит disk/network на main thread — включаем с penaltyFlashScreen() в debug-сборке.

Типичные проблемы с потоками

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

Thread explosion возникает при массовом создании потоков через GCD без ограничений. Система начинает агрессивно выделять потоки, вызывая резкую деградацию производительности при нагрузке. Решение — ограниченный 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. Actor в 2 раза надёжнее ручной синхронизации с NSLock.

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() } 

Почему structured concurrency — основа оптимизации конкурентности?

Structured concurrency (async/await в Swift, Kotlin Coroutines с корутинным скоупом) гарантирует отмену задач при завершении контекста, исключает утечки потоков и упрощает чтение кода. В отличие от GCD/Thread, где легко создать thread explosion или deadlock, structured concurrency принуждает к локальной области видимости задач. Actor в Swift обеспечивает изоляцию данных на уровне компилятора, что в 2 раза снижает количество race conditions по сравнению с ручной синхронизацией.

Инструменты диагностики

Инструмент Платформа Что находит
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, их стеки

Сравнение подходов к синхронизации

Подход Безопасность Производительность Сложность
NSLock / os_unfair_lock Средняя (ручная) Высокая Низкая
DispatchQueue concurrent + barrier Средняя Высокая Средняя
Actor (Swift) Высокая (компилятор) Средняя Низкая
Kotlin Mutex Высокая Высокая Средняя

Кейс из нашей практики: 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. После исправления deadlock исчез, время отклика сократилось на 40%.

Этапы работы

  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 под нагрузкой

Что входит в работу

  • Полный аудит конкурентности с отчётом по найденным проблемам
  • Исправление кода: замена GCD на async/await, внедрение actor, оптимизация coroutines
  • Документация по изменениям и рекомендации по дальнейшей разработке
  • Доступ к репозиторию с исправлениями, обучение команды (до 2 часов)
  • Гарантия на исправления — 3 месяца после сдачи

Сроки и как начать

Аудит конкурентности — 2–4 дня. Исправление найденных проблем — от 3 до 14 дней в зависимости от глубины архитектурных решений. Стоимость рассчитывается индивидуально. Если у вас есть подозрения на deadlock или race condition — свяжитесь с нами, оценим проект за 2 дня. Закажите аудит конкурентности сегодня и получите детальный отчёт с предложениями по исправлению.