Ce face suspend
O funcție suspend poate să-și întrerupă execuția la un punct (de exemplu cât așteaptă un răspuns din rețea) și să continue mai târziu de unde a rămas, fără să țină blocat firul de execuție. O funcție suspend poate fi apelată doar din altă funcție suspend sau dintr-o corutină. Din main obișnuit, apelul direct nu compilează.
Compilatorul transformă fiecare funcție suspend într-o funcție care primește un parametru ascuns, Continuation: „ce trebuie făcut după”. Biblioteca standard oferă doar piesele de bază: startCoroutine, suspendCoroutine, Continuation, sequence { }. În practică se folosește biblioteca separată kotlinx.coroutines, cu runBlocking, launch, async și delay.
Exemplele 1 și 2 folosesc doar biblioteca standard și rulează aici. Exemplul 3 folosește kotlinx.coroutines, care nu este instalată pe serverul care verifică exemplele; rezultatul lui este scris de mână.
Exemple
Exemplul 1: Pornirea unei funcții suspend cu biblioteca standard
startCoroutine pornește lambda suspend. Când se termină, se apelează Continuation cu rezultatul. Aici nicio funcție nu se suspendă cu adevărat, deci totul rulează imediat.
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.startCoroutine
suspend fun pretProdus(produs: String): Int = when (produs) {
"caiet" -> 7
"pix" -> 3
else -> 10
}
suspend fun totalCos(): Int = pretProdus("caiet") * 2 + pretProdus("pix")
fun main() {
val bloc: suspend () -> Int = { totalCos() }
bloc.startCoroutine(Continuation(EmptyCoroutineContext) { rezultat ->
println("Total coș: ${rezultat.getOrThrow()} lei")
})
println("main s-a terminat")
}
Rezultat
Total coș: 17 lei
main s-a terminat
Exemplul 2: Suspendare reală cu suspendCoroutine
asteaptaMesaj se suspendă și păstrează continuarea. main continuă între timp, iar resume trezește corutina exact de unde a rămas.
import kotlin.coroutines.Continuation
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.startCoroutine
import kotlin.coroutines.suspendCoroutine
var inAsteptare: Continuation<String>? = null
suspend fun asteaptaMesaj(): String = suspendCoroutine { cont -> inAsteptare = cont }
fun main() {
val bloc: suspend () -> Unit = {
println("1. Corutina pornește și așteaptă un mesaj")
val mesaj = asteaptaMesaj()
println("3. Corutina a primit: $mesaj")
}
bloc.startCoroutine(Continuation(EmptyCoroutineContext) { println("4. Corutina s-a terminat") })
println("2. main lucrează cât timp corutina e suspendată")
inAsteptare?.resume("Comanda #1024 a fost livrată în Iași")
}
Rezultat
1. Corutina pornește și așteaptă un mesaj
2. main lucrează cât timp corutina e suspendată
3. Corutina a primit: Comanda #1024 a fost livrată în Iași
4. Corutina s-a terminat
Exemplul 3: Cu biblioteca kotlinx.coroutines (nu rulează aici)
Cu dependența org.jetbrains.kotlinx:kotlinx-coroutines-core: delay este o funcție suspend care așteaptă fără să blocheze firul, iar async pornește cele două descărcări în paralel. Totalul durează cât cea mai lungă, nu cât suma lor.
import kotlinx.coroutines.*
suspend fun descarca(fisier: String, ms: Long): String {
delay(ms)
return "$fisier ($ms ms)"
}
fun main() = runBlocking {
val start = System.currentTimeMillis()
val a = async { descarca("facturi.pdf", 300) }
val b = async { descarca("poze.zip", 500) }
println("Gata: ${a.await()}, ${b.await()}")
println("Durată totală: ~${(System.currentTimeMillis() - start) / 100 * 100} ms")
}
Rezultat (cu kotlinx.coroutines instalată)
Gata: facturi.pdf (300 ms), poze.zip (500 ms)
Durată totală: ~500 ms
Greșeli frecvente
- Apelarea unei funcții
suspenddinmainobișnuit: eroaresuspend function 'suspend fun x(): Int' can only be called from a coroutine or another suspend function. Fie facisuspend fun main(), fie pornești o corutină. - Credința că
suspendface codul să ruleze pe alt fir: cuvântul doar permite suspendarea. Pe ce fir rulează codul decide cine pornește corutina (de exempluDispatchers.IOîn kotlinx.coroutines). - Folosirea lui
Thread.sleepîntr-o funcțiesuspend: blochează firul. Cu kotlinx.coroutines foloseștedelay.
Comenzi înrudite
Corutine (ideea): O corutină este un calcul care se poate opri și relua; Kotlin o folosește pentru generatoare (sequence) și pentru cod asincron simplu.sequence: Construiește o secvență dintr-un bloc de cod care dă valori una câte una cu yield; codul se oprește și continuă la cerere.lambda: O lambda este o funcție fără nume, scrisă între acolade, pe care o poți pune într-o variabilă sau trimite altei funcții.inline, noinline și crossinline: inline copiază corpul funcției și lambda-urile ei în locul apelului; noinline și crossinline controlează lambda-urile primite.