← Назад к вопросам

Что будет после вызова await у отмененной корутины запущенной с помощью async?

3.0 Senior🔥 114 комментариев
#Kotlin основы#Многопоточность и асинхронность

Комментарии (4)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Поведение await у отменённой async-корутины

При вызове await на Deferred (результате корутины, запущенной с помощью async), которая была отменена до или во время выполнения, поведение зависит от нескольких факторов: состояния корутины, контекста выполнения и способа обработки исключений.

Ключевые аспекты поведения

  1. Исключение CancellationException

    • await() бросит CancellationException, если корутина была отменена до завершения.
    • Это происходит потому, что отмена в Kotlin корутинах распространяется через иерархию и прерывает вычисления.
  2. Отмена до вызова await()

    suspend fun main() = runBlocking {
        val deferred = async {
            delay(1000)
            "Result"
        }
        
        deferred.cancel() // Отменяем до завершения
        
        try {
            val result = deferred.await()
            println("Result: $result")
        } catch (e: CancellationException) {
            println("Coroutine was cancelled: ${e.message}")
        }
    }
    

    В этом случае await() немедленно бросит CancellationException.

  3. Отмена во время выполнения await()

    suspend fun main() = runBlocking {
        val deferred = async {
            try {
                delay(5000) // Длительная операция
                "Success"
            } finally {
                println("Cleaning up resources")
                delay(1000) // Приостановка в finally блоке
            }
        }
        
        launch {
            delay(1000)
            deferred.cancel() // Отменяем во время выполнения
        }
        
        try {
            val result = deferred.await()
            println("Result: $result")
        } catch (e: CancellationException) {
            println("Await failed with cancellation")
        }
    }
    

    Даже если отмена происходит во время выполнения await(), исключение будет брошено после завершения всех finally блоков.

Важные особенности

  • Немедленное распространение отмены: Как только вызывается cancel(), Deferred переходит в отменённое состояние, и последующий await() бросит исключение.

  • Влияние контекста: Если корутина была запущена в контексте, который игнорирует отмену (например, NonCancellable), поведение может отличаться:

    val deferred = async(NonCancellable) {
        delay(3000)
        "Completed despite cancellation"
    }
    
  • Состояние Deferred: Можно проверить состояние перед вызовом await():

    if (deferred.isCancelled) {
        println("Coroutine was cancelled")
    }
    
  • Обработка с помощью awaitCancellation(): В некоторых сценариях можно явно ожидать отмены:

    val deferred = async {
        try {
            // Вычисления
        } finally {
            awaitCancellation() // Явное ожидание отмены
        }
    }
    

Практические рекомендации

  1. Всегда обрабатывайте исключения при вызове await():

    try {
        val result = deferred.await()
        // Обработка результата
    } catch (e: CancellationException) {
        // Специфичная обработка отмены
    } catch (e: Exception) {
        // Обработка других исключений
    }
    
  2. Используйте withTimeout для контроля времени выполнения:

    val result = withTimeout(1000) {
        deferred.await()
    }
    
  3. Проверяйте isCompleted и isCancelled перед вызовом await() для более предсказуемого поведения.

  4. Учитывайте иерархию отмены: Отмена родительской корутины автоматически отменяет все дочерние async-корутины.

Выводы

Вызов await() на отменённой async-корутине всегда приводит к выбрасыванию CancellationException, если только корутина не была запущена в контексте, игнорирующем отмену. Это поведение соответствует философии Kotlin корутин, где отмена — это кооперативный механизм, требующий корректной обработки со стороны разработчика. Правильная обработка этих исключений важна для создания устойчивых асинхронных приложений.