Что будет после вызова await у отмененной корутины запущенной с помощью async?
Комментарии (4)
Ответ сгенерирован нейросетью и может содержать ошибки
Поведение await у отменённой async-корутины
При вызове await на Deferred (результате корутины, запущенной с помощью async), которая была отменена до или во время выполнения, поведение зависит от нескольких факторов: состояния корутины, контекста выполнения и способа обработки исключений.
Ключевые аспекты поведения
-
Исключение
CancellationExceptionawait()броситCancellationException, если корутина была отменена до завершения.- Это происходит потому, что отмена в Kotlin корутинах распространяется через иерархию и прерывает вычисления.
-
Отмена до вызова
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. -
Отмена во время выполнения
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() // Явное ожидание отмены } }
Практические рекомендации
-
Всегда обрабатывайте исключения при вызове
await():try { val result = deferred.await() // Обработка результата } catch (e: CancellationException) { // Специфичная обработка отмены } catch (e: Exception) { // Обработка других исключений } -
Используйте
withTimeoutдля контроля времени выполнения:val result = withTimeout(1000) { deferred.await() } -
Проверяйте
isCompletedиisCancelledперед вызовомawait()для более предсказуемого поведения. -
Учитывайте иерархию отмены: Отмена родительской корутины автоматически отменяет все дочерние
async-корутины.
Выводы
Вызов await() на отменённой async-корутине всегда приводит к выбрасыванию CancellationException, если только корутина не была запущена в контексте, игнорирующем отмену. Это поведение соответствует философии Kotlin корутин, где отмена — это кооперативный механизм, требующий корректной обработки со стороны разработчика. Правильная обработка этих исключений важна для создания устойчивых асинхронных приложений.