> В чем отличие launch от async в Kotlin Coroutines (Kotlin, Android)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: MTS, Rutube, IBS

Стек: Kotlin, Android

> Пример ответа

Короткий ответ

launch и async - оба способа запустить корутину, но с разным назначением. launch возвращает Job и предназначен для fire-and-forget задач, которые не возвращают результат. async возвращает Deferred (наследник Job), который позволяет получить результат через await(). Основной trade-off: async добавляет оверхед на создание Deferred, поэтому для задач без результата используйте launch.

Подробное объяснение

launch - это builder, который запускает корутину и немедленно возвращает управление. Возвращаемый Job позволяет отменять корутину, но не предоставляет доступа к результату её выполнения. Исключения внутри launch пробрасываются в родительский контекст сразу (если не перехвачены).

async - это builder, который возвращает Deferred<T> - promise-подобный объект. Результат вычисляется асинхронно, и вы можете получить его через await(). await() приостанавливает текущую корутину до завершения вычисления. Исключения внутри async не пробрасываются сразу - они хранятся в Deferred и выбрасываются при вызове await().

Ключевые различия:

  • Возвращаемый тип: Job vs Deferred<T>
  • Назначение: side-effect операции vs вычисление результата
  • Обработка исключений: немедленная vs отложенная до await()
  • async без await() - это анти-паттерн, если только вы не используете structured concurrency с явной отменой

На практике

В Android-разработке launch используется для операций с UI: обновление View, запись в БД, отправка аналитики. async - для параллельного выполнения независимых вычислений, когда нужен результат: например, загрузка данных из нескольких источников с последующей агрегацией.

Типичный паттерн - async внутри coroutineScope для параллельного выполнения:

coroutineScope {
    val user = async { fetchUser() }
    val posts = async { fetchPosts() }
    show(user.await(), posts.await())
}

Здесь оба запроса выполняются параллельно, а await() последовательно собирает результаты.

Важно: async без await() создаёт утечку ресурсов, если корутина не отменяется. В Android это критично при работе с ViewModel - используйте viewModelScope и отменяйте через Job.

Пример кода

// launch - fire-and-forget
fun loadData() {
    viewModelScope.launch {
        repository.saveData() // результат не нужен
    }
}

// async - нужен результат
fun loadUserAndPosts() {
    viewModelScope.launch {
        val user = async { repository.getUser() }
        val posts = async { repository.getPosts() }
        // оба запроса выполняются параллельно
        val result = combine(user.await(), posts.await())
        _uiState.value = result
    }
}

// Обработка исключений
fun handleErrors() {
    viewModelScope.launch {
        try {
            val data = async { riskyOperation() }.await()
        } catch (e: Exception) {
            // исключение из async ловится здесь
        }
    }
}

Как отвечать на собеседовании

Начните с чёткого разграничения: launch - для задач без результата, async - для задач с результатом. Затем добавьте про Deferred и await(). Упомяните structured concurrency и важность отмены корутин. Приведите пример из реальной практики - параллельная загрузка данных. Если спросят про исключения - объясните разницу в propagation. Завершите trade-off: async имеет смысл только когда вы действительно используете результат, иначе это лишний оверхед.

Что проверяет интервьюер

  • Понимание базовых концепций coroutines: Job, Deferred, structured concurrency
  • Умение выбирать правильный builder под задачу
  • Знание особенностей обработки исключений
  • Понимание lifecycle корутин и важности отмены
  • Практический опыт: параллельное выполнение, await(), работа с viewModelScope

Типичные ошибки

  • Использование async для задач без результата - лишний оверхед и сложность
  • Забывание await() - результат теряется, корутина выполняется впустую
  • Игнорирование исключений из async - они не всплывают автоматически
  • Вызов async вне coroutineScope - потеря structured concurrency
  • Путаница между Deferred и Job при отмене корутин
  • Использование async для последовательных операций - лучше просто launch с suspend-функциями

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью