Propagacja anulowania w hierarchiach korutyn
Poznaj przepływ anulowania w relacjach nadrzędny–podrzędny między korutynami.
Propagacja anulowania w hierarchiach korutyn to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Relacja rodzic–dziecko
Gdy korutyna uruchamia inną korutynę za pomocą launch, dziecko dołącza do obiektu Job rodzica. Anulowanie rodzica anuluje wszystkie dzieci.
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
launch { delay(1000); println("child 1") }
launch { delay(1000); println("child 2") }
delay(1000)
println("parent")
}
delay(50)
parent.cancel()
parent.join()
println("All cancelled")
}Błąd dziecka anuluje rodzica
Jeśli dziecko zgłosi wyjątek inny niż wyjątek anulowania, anuluje rodzica i całe rodzeństwo — jest to domyślne zachowanie obiektu Job.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
launch {
delay(50)
throw RuntimeException("child failed")
}
launch {
delay(1000)
println("sibling — never prints")
}
}
} catch (e: RuntimeException) {
println("Caught: ${e.message}")
}
}Anulowanie nie propaguje się w górę
Anulowanie dziecka NIE anuluje rodzica. Tylko nieobsłużone wyjątki propagują się w górę. Rodzic może w dowolnym momencie anulować dziecko.
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
val child = launch {
delay(1000)
println("child done")
}
delay(50)
child.cancel() // cancels child
child.join()
println("parent still running") // parent is fine
}
parent.join()
}coroutineScope a GlobalScope
coroutineScope tworzy zakres podrzędny: anulowanie i błędy propagują się w jego obrębie. GlobalScope tworzy osierocone korutyny bez rodzica — należy unikać go w środowisku produkcyjnym.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
launch { delay(50); throw RuntimeException("error") }
}
} catch (e: Exception) {
println("coroutineScope propagated: ${e.message}")
}
// GlobalScope.launch { } would NOT propagate to runBlocking
}Anulowanie poddrzewa
Każde wywołanie launch lub async zwraca obiekt Job. Anuluj zadanie, aby anulować całe jego poddrzewo, w tym wszystkie zagnieżdżone wywołania launch.
import kotlinx.coroutines.*
fun main() = runBlocking {
val root = launch {
launch {
launch { delay(1000); println("deep") }
delay(1000)
}
}
delay(50)
root.cancel()
root.join()
println("Whole subtree cancelled")
}join() po cancel()
Zawsze wywołuj join() po cancel(), aby zaczekać na całkowite zatrzymanie korutyny i jej dzieci przed kontynuowaniem działania.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try { delay(1000) }
finally { println("cleanup ran") }
}
delay(50)
job.cancel()
job.join() // waits for finally to complete
println("Proceeded after join")
}cancelAndJoin()
job.cancelAndJoin() to wygodna funkcja, która anuluje zadanie, a następnie wykonuje join; jest równoważna wywołaniom cancel() + join().
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try { delay(1000) }
finally { println("cleanup") }
}
delay(50)
job.cancelAndJoin() // cancel + join in one call
println("Done")
}Propagacja przez async
W przypadku async wyjątki są przechowywane w obiekcie Deferred i zgłaszane podczas wywołania await(). Jeśli nie zostaną obsłużone, nadal propagują się do rodzica.
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
val d = async { throw RuntimeException("async fail") }
d.await() // rethrows here
}
} catch (e: RuntimeException) {
println("Caught from async: ${e.message}")
}
}Gwarancja programowania współbieżnego ustrukturyzowanego
Programowanie współbieżne ustrukturyzowane gwarantuje, że po zakończeniu zakresu wszystkie jego dzieci również zostały zakończone. Korutyny nie wyciekają — albo kończą działanie, albo zostają anulowane.
import kotlinx.coroutines.*
suspend fun doWork() = coroutineScope {
launch { delay(100); println("work 1") }
launch { delay(200); println("work 2") }
// both children complete before doWork returns
}
fun main() = runBlocking {
doWork()
println("All work done")
}Diagram propagacji anulowania
Hierarchia: anulowanie rodzica → anulowanie wszystkich dzieci. Anulowanie dziecka → tylko jego poddrzewo. Wyjątek dziecka → anulowanie rodzica → anulowanie rodzeństwa.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Parent
launch {
val c1 = launch { delay(1000); println("c1") } // child 1
val c2 = launch { delay(1000); println("c2") } // child 2
delay(50)
c1.cancel() // only c1 cancelled
c1.join()
println("c2 still active: ${c2.isActive}")
c2.cancelAndJoin()
}.join()
}Cykl życia CoroutineScope w Androidzie
W systemie Android obiekt viewModelScope zostaje anulowany po usunięciu obiektu ViewModel. Wszystkie uruchomione korutyny są anulowane automatycznie — nie trzeba ręcznie zwalniać zasobów.
import kotlinx.coroutines.*
// Pseudocode:
// class MyViewModel : ViewModel() {
// fun load() = viewModelScope.launch {
// val data = repo.fetch() // cancelled if VM cleared
// _state.value = data
// }
// }
fun main() = runBlocking { println("viewModelScope cancels on ViewModel.onCleared()") }Szybkie sprawdzenie
Co dzieje się z korutynami będącymi rodzeństwem, gdy dziecko zgłosi nieobsłużony wyjątek w ramach zwykłego obiektu Job?
Podsumowanie
Anulowanie rodzica kaskadowo anuluje wszystkie dzieci. Błąd dziecka propaguje się do rodzica i rodzeństwa (w przypadku zwykłego obiektu Job). Używaj cancelAndJoin(), aby poprawnie zakończyć działanie. Programowanie współbieżne ustrukturyzowane gwarantuje brak wycieków korutyn.
Często zadawane pytania
Czy lekcja „Propagacja anulowania w hierarchiach korutyn” jest bezpłatna?
Tak — pełny tekst „Propagacja anulowania w hierarchiach korutyn” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Propagacja anulowania w hierarchiach korutyn”?
Poznaj przepływ anulowania w relacjach nadrzędny–podrzędny między korutynami. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Propagacja anulowania w hierarchiach korutyn”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Kooperatywne anulowanie: isActive i ensureActive
- withTimeout i withTimeoutOrNull
- Sprzątanie za pomocą finally i NonCancellable
- Propagacja anulowania w hierarchiach korutyn