0Pricing
Kotlin Academy · Lezione

Propagazione della cancellazione nelle gerarchie di coroutine

Comprenda come la cancellazione si propaga tra coroutine genitrici e figlie.

Propagazione della cancellazione nelle gerarchie di coroutine è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.

Relazione tra genitore e figlia

Quando una coroutine ne avvia un'altra con launch, la coroutine figlia si unisce al Job della coroutine padre. La cancellazione del genitore annulla tutte le figlie.

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")
}

Il fallimento di una figlia annulla il genitore

Se una coroutine figlia genera un'eccezione diversa dalla cancellazione, annulla il genitore e tutte le coroutine sorelle: questo è il comportamento predefinito di 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}")
    }
}

La cancellazione non si propaga verso l'alto

La cancellazione di una coroutine figlia NON annulla quella padre. Solo le eccezioni non gestite lo fanno. Una coroutine padre può annullare una figlia in qualsiasi momento.

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 e GlobalScope

coroutineScope crea uno scope figlio: la cancellazione e gli errori si propagano. GlobalScope crea coroutine orfane senza genitore: lo eviti in produzione.

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
}

Cancellazione di un sottoalbero

Ogni launch o async restituisce un Job. Annulli un job per annullare l'intero sottoalbero, comprese eventuali coroutine avviate al suo interno.

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() dopo cancel()

Chiami sempre join() dopo cancel() per attendere che la coroutine e le sue figlie si arrestino completamente prima di proseguire.

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() è una funzione di utilità che annulla e poi attende la conclusione, equivalente a 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")
}

Propagazione tramite async

Con async, le eccezioni vengono memorizzate nel Deferred e generate quando chiama await(). Continuano comunque a propagarsi al genitore se non vengono gestite.

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}")
    }
}

Garanzia della concorrenza strutturata

La concorrenza strutturata garantisce che, quando uno scope termina, tutte le sue coroutine figlie siano terminate. Nessuna coroutine sfugge al controllo: o completa l'esecuzione oppure viene cancellata.

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")
}

Diagramma della propagazione della cancellazione

La gerarchia: annullamento del genitore → tutte le coroutine figlie annullate. Annullamento di una figlia → solo il relativo sottoalbero. Eccezione di una figlia → genitore annullato → coroutine sorelle annullate.

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()
}

Ciclo di vita di CoroutineScope in Android

In Android, viewModelScope viene cancellato quando il ViewModel viene eliminato. Tutte le coroutine avviate vengono cancellate automaticamente: non è necessaria alcuna pulizia manuale.

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()") }

Verifica rapida

Che cosa accade alle coroutine sorelle quando una figlia genera un'eccezione non gestita sotto un Job normale?

Riepilogo

La cancellazione del genitore si propaga a tutte le coroutine figlie. Il fallimento di una figlia si propaga al genitore e alle coroutine sorelle (con un Job normale). Utilizzi cancelAndJoin() per un arresto ordinato. La concorrenza strutturata garantisce che non ci siano coroutine disperse.

Domande Frequenti

La lezione «Propagazione della cancellazione nelle gerarchie di coroutine» è gratuita?

Sì — il testo completo di «Propagazione della cancellazione nelle gerarchie di coroutine» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.

Cosa imparerò in «Propagazione della cancellazione nelle gerarchie di coroutine»?

Comprenda come la cancellazione si propaga tra coroutine genitrici e figlie. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Kotlin Academy?

Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Propagazione della cancellazione nelle gerarchie di coroutine»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?

Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Cancellazione cooperativa: isActive ed ensureActive
  2. withTimeout e withTimeoutOrNull
  3. Pulizia con finally e NonCancellable
  4. Propagazione della cancellazione nelle gerarchie di coroutine
← Torna a Kotlin Academy