← Назад к вопросам
Отменится async при выбросе исключения если внутри async лежит launch в корутинах
1.7 Middle🔥 131 комментариев
#Многопоточность и асинхронность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Отмена async при исключении в вложенном launch
Короткий ответ
Нет, async не отменится, если исключение выброшено в вложенном launch. Это ключевая разница в обработке исключений между async и launch.
Почему?
launch и async имеют разные стратегии обработки исключений:
launch — пробрасывает исключения вверх (propagates exceptions)
- Необработанное исключение отменяет всю корутину
- Отменяет всех родителей и sibling корутины
async — захватывает исключения в результат (suspends exceptions)
- Исключение не пробрасывается автоматически
- Исключение доступно только при вызове await()
- Вложенный launch не может отменить родительский async
Пример 1: launch внутри async
scope.async {
println("Async начался")
launch {
println("Launch начался")
throw Exception("Ошибка в launch")
println("Эта строка не выполнится")
}
println("Async продолжает работу после launch")
}.await() // Не выбросит исключение!
// Вывод:
// Async начался
// Launch начался
// Async продолжает работу после launch
// Исключение потеряно!
Почему async не отменится?
val job = scope.async {
// async = Deferred<T>
// Исключения находятся внутри результата
launch {
// launch = Job
// Исключения пробрасываются наружу
// Но async их не слушает!
throw Exception()
}
// async продолжает работу
"Результат"
}
job.await() // Вернёт "Результат", исключение потеряно
Пример 2: Правильная обработка
scope.async {
try {
launch {
throw Exception("Ошибка")
}.join() // Ждём завершения launch
} catch (e: Exception) {
println("Поймали: ${e.message}")
}
}.await()
// Или лучше:
scope.async {
val result = supervisorScope {
launch {
throw Exception("Ошибка")
}
}
}
Пример 3: Что ДЕЙСТВИТЕЛЬНО отменит async
// Исключение в самом async
scope.async {
throw Exception("Ошибка здесь")
}.await() // Выбросит исключение!
// launch не может отменить async, но:
val deferred = scope.async { ... }
deferred.cancel() // Явная отмена
Иерархия корутин
scope (parent)
├─ async (captures exceptions)
│ └─ launch (propagates exceptions)
│ └─ Exception выброшена
│
// launch не может отменить async!
// launch отменится, но async продолжит работу
Правила обработки исключений
| Ситуация | launch | async |
|---|---|---|
| Exception в корутине | Отменяет parent | Сохраняется в Deferred |
| Вложенный launch выбросит | Отменяет всех | Не влияет на async |
| Вложенный async выбросит | Требует await() | Не влияет |
| try-catch работает | ✅ Да | ✅ Да |
CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { context, exception ->
println("Перехвачено: ${exception.message}")
}
scope.async(handler) {
launch {
throw Exception("В launch")
}
// handler НЕ сработает! Exception в launch, не в async
}.await()
// Для launch это работает:
scope.launch(handler) {
throw Exception()
// handler СРАБОТАЕТ!
}
Вывод
async НЕ отменится, если исключение выброшено в вложенном launch, потому что:
- async захватывает исключения в результат
- launch пробрасывает исключения вверх
- async не слушает исключения от launch
- Нужна явная обработка через try-catch или .join()
Рекомендация: если важно обработать исключение из launch, используй try-catch или supervisorScope.