suspend function: vad är det, syntax och funktion i korutiner

Författare: IT Sectr Publicerad: 2026-06-22 Lästid: 9 min

Suspend function — är en funktion med suspend-modifieraren som kan pausa sin exekvering utan att blockera tråden och återupptas senare i samma korutin. Enligt JetBrains Kotlin Docs, 2025 är suspend-funktioner den grundläggande byggstenen för korutiner och tillhandahåller asynkronitet utan callbacks. Varje suspend-funktion kompileras till en tillståndsmaskin baserad på Continuation, vilket möjliggör effektiv hantering av pauspunkter.

Huvudpunkter

  • Suspend — Kotlin-nyckelord som markerar en funktion som pausbar (asynkron)
  • Continuation — dold parameter som kompilatorn lägger till varje suspend-funktion för att bevara tillstånd
  • Pauspunkter — platser där andra suspend-funktioner anropas, där korutinen kan stanna utan blockering
  • Tillståndsmaskin — intern representation av en suspend-funktion, där varje pauspunkt är ett separat tillstånd
  • Anrop endast från korutin — suspend-funktioner kan endast anropas från en annan suspend-funktion eller från launch/async

Vad är suspend function i Kotlin?

Suspend function — är en funktion deklarerad med nyckelordet suspend som kan pausa exekvering i en eller flera punkter utan att blockera tråden. Varje anrop av en suspend-funktion inuti en annan suspend-funktion är en potentiell pauspunkt.

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

Kotlin-kompilatorn översätter en sådan funktion till en tillståndsmaskin. Varje pauspunkt (anrop av en annan suspend-funktion) blir ett tillstånd (label). Den aktuella tråden frigörs mellan tillstånden och efter slutförandet av den förväntade operationen fortsätter exekveringen från nästa tillstånd.

Historik

Suspend-funktioner dök upp i Kotlin 1.3 (2018) tillsammans med korutiner som en experimentell funktion och blev stabila i Kotlin 1.5 (2021). Före detta tillhandahölls asynkronitet i Kotlin/Java via callbacks, RxJava och CompletableFuture. Suspend-funktioner erbjöd ett alternativ med linjär syntax och automatisk trådhantering.

Hur fungerar suspend-funktioner: Continuation och tillståndsmaskin

Att förstå den interna strukturen hos suspend-funktioner är nyckeln till att arbeta korrekt med korutiner. Till skillnad från vanliga funktioner kompileras varje suspend-funktion till en klass med Continuation-gränssnitt.

Continuation — den dolda parametern

Kotlin-kompilatorn lägger till en parameter av typen Continuation i slutet av varje parameter i en suspend-funktion. Continuation innehåller:

  • context — CoroutineContext (dispatcher, job, kontextelement)
  • resumeWith — metod för att återuppta exekvering med resultat eller undantag
  • label — index för aktuellt tillstånd i tillståndsmaskinen

Tillståndsmaskin med exempel

Anta att vi har en suspend-funktion med två anrop till andra suspend-funktioner:

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

Kompilatorn omvandlar den till en tillståndsmaskin med etiketter:

kotlin
// Förenklad representation av genererad kod
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
        }
    }
}

Viktig observation: om funktionen returnerar COROUTINE_SUSPENDED frigörs den aktuella tråden. När den asynkrona operationen är slutförd anropas Continuation.resumeWith och tillståndsmaskinen fortsätter från nästa label.

Syntax för suspend-funktioner: deklaration och anrop

Deklarationen av en suspend-funktion skiljer sig inte från en vanlig, förutom nyckelordet suspend före fun. Det finns bara en begränsning: en suspend-funktion kan endast anropas från en korutin eller en annan suspend-funktion.

Grundläggande deklaration

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

I detta exempel är delay också en suspend-funktion som pausar korutinen under ett angivet antal millisekunder utan att blockera tråden. Efter fördröjningen återupptas exekveringen.

Anrop från korutin

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

runBlocking skapar en bro mellan den vanliga världen och korutiner. Inuti lambdan är anrop av valfri suspend-funktion tillåtet.

Suspend-lambdor och funktionella typer

Kotlin stöder suspend-versioner av funktionella typer — suspend () -> T och suspend (A) -> B. Detta gör det möjligt att skicka asynkrona lambdor till högre ordningens funktioner:

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

Funktionen withRetry accepterar en suspend-lambda och upprepar dess exekvering vid fel. Detta är ett typiskt mönster för nätverksförfrågningar med återförsök.

Skillnader mellan suspend-funktioner och vanliga

Skillnaderna mellan suspend och vanliga funktioner går utöver att bara lägga till en modifierare. Låt oss undersöka de grundläggande skillnaderna.

EgenskapVanlig funktionSuspend-funktion
ExekveringstrådBlockerar tråden tills klarKan frigöra tråden och återuppta senare
KompilatorparametrarEndast angivna parametrarImplicit Continuation i slutet
Anrop från vanlig funktionJaNej
StackFysisk trådstackTillståndsmaskin på heap + fysisk stack mellan punkter
ReturDirekt värdeVärde eller COROUTINE_SUSPENDED
PrestandaMinimal overhead~några nanosekunder för tillståndsmaskin (Kotlin 1.9+)

Varför suspend-funktioner inte kan anropas från vanliga funktioner

En vanlig funktion har ingen Continuation — ingen plats att spara tillstånd och återuppta exekvering. Om du behöver anropa en suspend-funktion från en vanlig funktion, använd runBlocking (för tester) eller CoroutineScope.launch (för produktion med hänsyn till livscykeln).

Exempel på suspend-funktioner i Android

Låt oss undersöka tre verkliga scenarier för användning av suspend-funktioner i Android-appar med Kotlin.

Exempel 1: Room DAO med suspend-frågor

Room stöder suspend-funktioner direkt — frågan körs automatiskt i bakgrunden:

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

    @Insert
    suspend fun insertUser(user: User)
}

Room använder internt Dispatchers.IO för att utföra frågan och resultatet returneras till den dispatcher där suspend-funktionen anropades.

Exempel 2: Komposition av suspend-funktioner för skärmladdning

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

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

ViewModelScope.launch skapar en korutin inom vilken suspend-funktionen getProfile anropas. Efter att resultatet erhållits uppdateras UI:t på huvudtråden.

Exempel 3: Sekventiella asynkrona steg

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

Tre suspend-funktioner körs sekventiellt. Vid varje steg kan korutinen stanna utan att blockera tråden. Om ett steg kastar ett undantag — körs inte de andra, vilket skyddar mot ogiltiga beställningstillstånd.

Vanliga misstag vid arbete med suspend-funktioner

Även erfarna Kotlin-utvecklare gör misstag vid design av suspend-funktioner. Låt oss titta på de vanligaste.

Misstag 1: Blockerande anrop i suspend

En suspend-funktion gör inte koden automatiskt asynkron. Thread.sleep(), InputStream.read() och andra blockerande anrop kommer fortfarande att blockera tråden. Använd withContext(Dispatchers.IO) för att omsluta blockerande operationer.

Misstag 2: Skapa suspend-funktioner i onödan

Om en funktion inte anropar andra suspend-funktioner och inte utför asynkrona operationer — är suspend-modifieraren överflödig. Den lägger till overhead för tillståndsmaskinen och begränsar anropskontexten. Gör en funktion suspend endast när den verkligen pausar.

Misstag 3: Ignorera CancellationException

Vid avbrytning av korutin kastar suspend-funktioner CancellationException. Fånga den inte tanklöst — du berövar den anropande koden möjligheten att korrekt slutföra avbrytningen. Om du behöver utföra en slutgiltig operation, använd ett finally-block och NonCancellable.

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

finally-blocket körs alltid, inklusive vid avbrytning, och NonCancellable garanterar att rensningen inte avbryts.

Misstag 4: Anropa suspend-funktioner från callbacks

En suspend-funktion kan inte anropas direkt från en callback utan att skapa en korutin. Använd suspendCoroutine eller suspendCancellableCoroutine för att anpassa callback-stil till korutiner.

Vanliga frågor

Kan en suspend-funktion sakna pauspunkter?

Ja, tekniskt sett kan en suspend-funktion inte anropa andra suspend-funktioner. Kompilatorn skapar en tillståndsmaskin med ett tillstånd (label 0). En sådan funktion har dock ingen praktisk nytta — den körs som en vanlig, men med overhead. Använd inte suspend i onödan.

Hur felsöker man suspend-funktioner?

Kotlin tillhandahåller kotlinx-coroutines-debug — ett bibliotek med DebugProbes och verktyg för korutinspårning. I Android Studio från och med version Arctic Fox finns en inbyggd flik Coroutines i Debugger som visar aktiva korutiner, deras tillstånd och pauspunkter.

Påverkar antalet suspend-punkter prestandan?

Varje pauspunkt skapar ett nytt tillstånd i tillståndsmaskinen. För de flesta applikationer är overhead för en punkt några nanosekunder (Kotlin 1.9+). Endast när det finns tiotusentals punkter i en loop är det värt att kombinera operationer eller använda sequence/flow.

Vad är skillnaden mellan suspend-funktion och async/await i andra språk?

I Kotlin är suspend en modifierare av funktionstypen, inte en markör för returvärdet (som async i C#). Varje suspend-funktion kan ha godtyckliga parametrar och returtyp, och dess anrop skiljer sig syntaktiskt inte från ett vanligt funktionsanrop — det finns ingen await-operator vid anropsplatsen.

Hur konverterar man en callback-funktion till suspend?

Använd suspendCancellableCoroutine för anpassning. Inuti skickar du callback-registreringen som anropar continuation.resume() och returnerar en avbrytningstoken om callbacken stöder avprenumeration. Detta är ett standardmönster för att omsluta gamla Android-API:er.

Sammanfattning

  • Suspend function — funktion med suspend-modifieraren som kan pausa exekvering utan att blockera tråden via Continuation-mekanismen
  • Tillståndsmaskin — intern representation av suspend-funktion i Kotlin-bytecode, där varje pauspunkt är ett separat tillstånd med label
  • Continuation — dold parameter som innehåller korutinkontexten och resumeWith-metoden för att återuppta exekvering
  • Anrop endast från korutin — suspend-funktioner är inte tillgängliga från vanliga funktioner utan runBlocking eller CoroutineScope
  • Blockerande operationer i suspend kräver withContext(Dispatchers.IO) — annars blockeras tråden
  • Room och Retrofit stöder suspend-funktioner inbyggt och hanterar automatiskt bakgrundstrådar
  • CancellationException — hantera avbrytning via finally + NonCancellable, fånga inte CancellationException tanklöst

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också