Что произойдет с родительским scope если завершится дочерняя корутина?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Влияние завершения дочерней корутины на родительский scope
В Kotlin корутинах поведение родительского scope при завершении дочерней корутины зависит от типа запуска (launch builder) и контекста выполнения. Рассмотрим ключевые варианты.
1. Независимое завершение (не влияет на родителя)
При стандартном запуске через launch в том же scope дочерняя корутина выполняется независимо. Родительский scope продолжит работу даже если дочерняя завершится (обычно или с ошибкой).
import kotlinx.coroutines.*
fun main() = runBlocking {
val parentScope = this
val childJob = parentScope.launch {
delay(500)
println("Дочерняя корутина завершилась")
}
println("Родительский scope активен")
delay(1000)
println("Родительский scope тоже завершился")
}
Здесь родительский scope (runBlocking) продолжает работу после завершения childJob.
2. Влияние через SupervisorJob
Если scope использует SupervisorJob, завершение дочерней корутины (особенно с исключением) не влияет на другие дочерние корутины и на сам scope.
val supervisorScope = CoroutineScope(SupervisorJob())
supervisorScope.launch {
throw Exception("Ошибка в дочерней!")
}
supervisorScope.launch {
delay(1000)
println("Эта корутина продолжит работу несмотря на ошибку в соседней")
}
3. Влияние через coroutineScope builder
Внутри функции coroutineScope создается новый под-scope, который ожидает завершения всех своих дочерних корутин. Если дочерняя завершится с ошибкой, этот под-scope завершится и распространит исключение на родителя.
fun main() = runBlocking {
try {
coroutineScope {
launch {
delay(100)
throw RuntimeException("Дочерняя ошибка")
}
launch {
delay(200)
println("Эта корутина не выполнится")
}
}
} catch (e: Exception) {
println("Родитель поймал исключение: ${e.message}")
}
}
Здесь coroutineScope завершится при ошибке в первой дочерней корутине, и исключение "поднимется" в родительский runBlocking.
4. Влияние через async и исключения
При использовании async исключение в дочерней корутине будет "запечатано" в Deferred и возникнет только при вызове await().
fun main() = runBlocking {
val deferred = async {
delay(100)
throw ArithmeticException("Ошибка в async")
}
delay(300)
try {
deferred.await()
} catch (e: Exception) {
println("Исключение получено при await: ${e.message}")
}
}
Родительский scope не завершится сразу при исключении в async, только при попытке получить результат.
Ключевые выводы:
- Обычный launch в общем scope: завершение дочерней корутины (даже с ошибкой) не завершает родительский scope.
- SupervisorJob: изолирует исключения, scope продолжает работу.
- coroutineScope builder: под-scope завершается при завершении любой дочерней корутины и влияет на родительскую корутину.
- async: исключение не влияет на scope до момента вызова
await(). - Главное правило: родительский scope продолжит работу, если не используется структура, которая явно распространяет исключения (как
coroutineScope), или если не все дочерние корутины являются частью такого под-scope.
Таким образом, в большинстве случаев родительский scope остается активным после завершения дочерней корутины. Проблемы возникают только при использовании определенных конструкций, которые предназначены для синхронизации и распространения ошибок.