suspend function: ce este, sintaxa și funcționarea în corutine

Autor: IT Sectr Publicat: 2026-06-22 Timp de citire: 9 min

Suspend function — este o funcție cu modificatorul suspend care își poate suspenda execuția fără a bloca firul de execuție și poate reveni mai târziu în aceeași corutină. Conform JetBrains Kotlin Docs, 2025, funcțiile suspend sunt elementul fundamental al corutinelor, asigurând asincronismul fără callback-uri. Fiecare funcție suspend este compilată într-o mașină de stări bazată pe Continuation, ceea ce permite gestionarea eficientă a punctelor de suspendare.

Principalele puncte

  • Suspend — cuvântul cheie Kotlin care marchează o funcție ca suspendabilă (asincronă)
  • Continuation — parametrul ascuns pe care compilatorul îl adaugă fiecărei funcții suspend pentru a păstra starea
  • Puncte de suspendare — locurile de apelare a altor funcții suspend unde corutina se poate opri fără blocare
  • Mașină de stări — reprezentarea internă a funcției suspend, unde fiecare punct de suspendare este o stare separată
  • Apel doar din corutină — funcțiile suspend pot fi apelate doar dintr-o altă funcție suspend sau din launch/async

Ce este suspend function în Kotlin?

Suspend function — este o funcție declarată cu cuvântul cheie suspend care poate suspenda execuția într-unul sau mai multe puncte fără a bloca firul de execuție. Fiecare apel al unei funcții suspend în interiorul altei funcții suspend este un potențial punct de suspendare.

kotlin
suspend fun fetchUserData(): User {
    val response = httpClient.get("/user")
    return parser.parse(response)
}

Compilatorul Kotlin transformă o astfel de funcție într-o mașină de stări. Fiecare punct de suspendare (apelul altei funcții suspend) devine o stare (label). Firul curent este eliberat între stări, iar după finalizarea operației așteptate, execuția se reia de la starea următoare.

Istoricul apariției

Funcțiile suspend au apărut în Kotlin 1.3 (2018) odată cu corutinele ca funcționalitate experimentală și au devenit stabile în Kotlin 1.5 (2021). Înainte de aceasta, asincronismul în Kotlin/Java era asigurat prin callback-uri, RxJava și CompletableFuture. Funcțiile suspend au oferit o alternativă cu sintaxă liniară și gestionare automată a firelor de execuție.

Cum funcționează funcțiile suspend: Continuation și mașina de stări

Înțelegerea structurii interne a funcțiilor suspend este cheia pentru a lucra corect cu corutinele. Spre deosebire de funcțiile obișnuite, fiecare funcție suspend este compilată într-o clasă cu interfața Continuation.

Continuation — parametrul ascuns

Compilatorul Kotlin adaugă un parametru de tip Continuation la sfârșitul fiecărui parametru al funcției suspend. Continuation conține:

  • context — CoroutineContext (dispecer, job, elemente de context)
  • resumeWith — metoda pentru reluarea execuției cu rezultat sau excepție
  • label — indicele stării curente în mașina de stări

Mașina de stări prin exemplu

Să presupunem că avem o funcție suspend cu două apeluri către alte funcții suspend:

kotlin
suspend fun process() {
    val a = stepOne()
    val b = stepTwo(a)
    println(b)
}

Compilatorul o transformă într-o mașină de stări cu etichete:

kotlin
// Reprezentare simplificată a codului generat
fun process(cont: Continuation<Unit>): Any? {
    val cont = cont as ProcessContinuation
    when (cont.label) {
        0 -> {
            cont.label = 1
            if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        1 -> {
            cont.label = 2
            val a = cont.result as TypeA
            if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        2 -> {
            println(cont.result)
            Unit
        }
    }
}

Observația cheie: dacă funcția returnează COROUTINE_SUSPENDED, firul curent este eliberat. Când operația asincronă se finalizează, Continuation.resumeWith este apelată, iar mașina de stări continuă de la următorul label.

Sintaxa funcțiilor suspend: declarare și apel

Declarația unei funcții suspend nu diferă de cea obișnuită, cu excepția cuvântului cheie suspend înainte de fun. Există o singură restricție: o funcție suspend poate fi apelată doar dintr-o corutină sau dintr-o altă funcție suspend.

Declarația de bază

kotlin
suspend fun delayAndReturn(ms: Long): String {
    delay(ms)
    return "Done after ${ms}ms"
}

În acest exemplu, delay este de asemenea o funcție suspend care oprește corutina pentru un număr specificat de milisecunde fără a bloca firul. După întârziere, execuția este reluată.

Apelul dintr-o corutină

kotlin
fun main() = runBlocking {
    val result = delayAndReturn(1000)
    println(result)
}

runBlocking creează o punte între lumea obișnuită și corutine. În interiorul lambda, este permis apelarea oricăror funcții suspend.

Lambda-uri suspend și tipuri funcționale

Kotlin suportă versiunile suspend ale tipurilor funcționale — suspend () -> T și suspend (A) -> B. Aceasta permite transmiterea lambda-urilor asincrone către funcții de ordin superior:

kotlin
suspend fun  withRetry(
    retries: Int = 3,
    block: suspend () -> T
): T {
    repeat(retries - 1) {
        try { return block() }
        catch (_: Exception) { delay(100) }
    }
    return block()
}

Funcția withRetry primește un lambda suspend și repetă execuția acestuia la erori. Este un model tipic pentru cererile de rețea cu reîncercări.

Cum se deosebesc funcțiile suspend de cele obișnuite

Diferențele dintre funcțiile suspend și cele obișnuite depășesc simpla adăugare a unui modificator. Să examinăm diferențele esențiale.

CaracteristicăFuncție obișnuităFuncție suspend
Fir de execuțieBlochează firul până la finalizarePoate elibera firul și relua mai târziu
Parametri compilatorDoar parametrii specificațiContinuation implicit la sfârșit
Apel din funcție obișnuităDaNu
StivăStiva fizică a firuluiMașină de stări în heap + stivă fizică între puncte
ReturnareValoare directăValoare sau COROUTINE_SUSPENDED
PerformanțăCosturi minime~câteva nanosecunde pentru mașina de stări (Kotlin 1.9+)

De ce funcțiile suspend nu pot fi apelate din funcții obișnuite

O funcție obișnuită nu are Continuation — nu are unde să salveze starea și cu ce să reia execuția. Dacă trebuie să apelați o funcție suspend dintr-o funcție obișnuită, utilizați runBlocking (pentru teste) sau CoroutineScope.launch (pentru producție, ținând cont de ciclul de viață).

Exemple de funcții suspend în Android

Să examinăm trei scenarii reale de utilizare a funcțiilor suspend în aplicații Android cu Kotlin.

Exemplul 1: Room DAO cu interogări suspend

Room suportă funcțiile suspend direct — interogarea se execută automat în fundal:

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUser(id: Int): User?

    @Insert
    suspend fun insertUser(user: User)
}

Room utilizează intern Dispatchers.IO pentru executarea interogării, iar rezultatul este returnat dispecerului în care a fost apelată funcția suspend.

Exemplul 2: Compunerea funcțiilor suspend pentru încărcarea ecranului

kotlin
class ProfileViewModel : ViewModel() {
    private val repo = ProfileRepository()

    fun loadProfile(id: String) {
        viewModelScope.launch {
            val profile = repo.getProfile(id)
            _profile.value = profile
        }
    }
}

ViewModelScope.launch creează o corutină în interiorul căreia este apelată funcția suspend getProfile. După obținerea rezultatului, UI este actualizat pe firul principal.

Exemplul 3: Pași asincroni secvențiali

kotlin
suspend fun placeOrder(cart: Cart): OrderResult {
    val validated = validateCart(cart)
    val payment = processPayment(validated)
    val receipt = sendReceipt(payment)
    return receipt
}

Trei funcții suspend se execută secvențial. La fiecare pas, corutina se poate opri fără a bloca firul. Dacă un pas generează o excepție — ceilalți nu se execută, ceea ce protejează împotriva stărilor incorecte ale comenzii.

Greșeli tipice la lucrul cu funcțiile suspend

Chiar și dezvoltatorii experimentați Kotlin fac greșeli la proiectarea funcțiilor suspend. Să analizăm cele mai frecvente.

Greșeala 1: Apeluri blocante în interiorul suspend

O funcție suspend nu face codul automat asincron. Thread.sleep(), InputStream.read() și alte apeluri blocante vor bloca totuși firul. Utilizați withContext(Dispatchers.IO) pentru a încapsula operațiile blocante.

Greșeala 2: Crearea funcțiilor suspend fără necesitate

Dacă o funcție nu apelează alte funcții suspend și nu execută operații asincrone — modificatorul suspend este redundant. Adaugă costuri suplimentare pentru mașina de stări și limitează contextul de apel. Faceți o funcție suspend doar atunci când se suspendă cu adevărat.

Greșeala 3: Ignorarea CancellationException

La anularea corutinei, funcțiile suspend aruncă CancellationException. Nu-l prindeți fără discernământ — lipsiți codul apelant de posibilitatea de a finaliza corect anularea. Dacă trebuie să executați o operație de finalizare, utilizați blocul finally și NonCancellable.

kotlin
suspend fun safeOperation() {
    try {
        doWork()
    } finally {
        withContext(NonCancellable) {
            cleanup()
        }
    }
}

Blocul finally se execută întotdeauna, inclusiv la anulare, iar NonCancellable garantează că cleanup-ul nu va fi întrerupt.

Greșeala 4: Apelarea funcțiilor suspend din callback-uri

Nu se poate apela o funcție suspend direct dintr-un callback fără a crea o corutină. Utilizați suspendCoroutine sau suspendCancellableCoroutine pentru a adapta stilul callback la corutine.

Întrebări frecvente

Poate o funcție suspend să nu conțină puncte de suspendare?

Da, tehnic o funcție suspend poate să nu apeleze alte funcții suspend. Compilatorul va crea o mașină de stări cu o singură stare (label 0). Totuși, o astfel de funcție nu are utilitate practică — se execută ca una obișnuită, dar cu costuri suplimentare. Nu utilizați suspend fără necesitate.

Cum se depanează funcțiile suspend?

Kotlin oferă kotlinx-coroutines-debug — o bibliotecă cu DebugProbes și instrumente de trasare a corutinelor. În Android Studio începând cu versiunea Arctic Fox există o filă încorporată Coroutines în Debugger care arată corutinele active, starea și punctele lor de suspendare.

Numărul punctelor suspend afectează performanța?

Fiecare punct de suspendare creează o stare nouă în mașina de stări. Pentru majoritatea aplicațiilor, costul unui punct este de unități de nanosecunde (Kotlin 1.9+). Doar la zeci de mii de puncte într-o buclă merită să combinați operațiile sau să utilizați sequence/flow.

Cu ce se deosebește funcția suspend de async/await în alte limbaje?

În Kotlin, suspend este un modificator al tipului de funcție, nu un marcator al valorii returnate (ca async în C#). Orice funcție suspend poate avea parametri și tip de returnare arbitrare, iar apelul său sintactic nu diferă de apelul unei funcții obișnuite — nu există operatorul await la locul apelului.

Cum se convertește o funcție callback în suspend?

Utilizați suspendCancellableCoroutine pentru adaptare. În interior, transmiteți înregistrarea callback-ului care apelează continuation.resume() și returnați un token de anulare dacă callback-ul suportă dezabonarea. Acesta este modelul standard pentru încapsularea API-urilor vechi Android.

Concluzii

  • Suspend function — funcție cu modificatorul suspend care poate suspenda execuția fără blocarea firului prin mecanismul Continuation
  • Mașină de stări — reprezentarea internă a funcției suspend în bytecodul Kotlin, unde fiecare punct de suspendare este o stare separată cu label
  • Continuation — parametrul ascuns care conține contextul corutinei și metoda resumeWith pentru reluarea execuției
  • Apel doar din corutină — funcțiile suspend nu sunt accesibile din funcții obișnuite fără runBlocking sau CoroutineScope
  • Operații blocante în interiorul suspend necesită withContext(Dispatchers.IO) — altfel firul este blocat
  • Room și Retrofit suportă nativ funcțiile suspend, gestionând automat firele de fundal
  • CancellationException — gestionați anularea prin finally + NonCancellable, nu prindeți CancellationException fără discernământ

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și