suspend function: τι είναι, σύνταξη και λειτουργία στα coroutines

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-06-22 Χρόνος ανάγνωσης: 9 λεπ

Suspend function — είναι μια συνάρτηση με τον τροποποιητή suspend που μπορεί να αναστείλει την εκτέλεσή της χωρίς να μπλοκάρει το νήμα και να συνεχίσει αργότερα στο ίδιο coroutine. Σύμφωνα με το JetBrains Kotlin Docs, 2025, οι συναρτήσεις suspend είναι το θεμελιώδες δομικό στοιχείο των coroutines, παρέχοντας ασυγχρονισμό χωρίς callback. Κάθε συνάρτηση suspend μεταγλωττίζεται σε μια μηχανή καταστάσεων βασισμένη στο Continuation, επιτρέποντας την αποτελεσματική διαχείριση των σημείων αναστολής.

Κύρια σημεία

  • Suspend — λέξη-κλειδί του Kotlin που χαρακτηρίζει μια συνάρτηση ως αναστρέψιμη (ασύγχρονη)
  • Continuation — κρυφή παράμετρος που προσθέτει ο μεταγλωττιστής σε κάθε συνάρτηση suspend για τη διατήρηση της κατάστασης
  • Σημεία αναστολής — σημεία κλήσης άλλων συναρτήσεων suspend όπου το coroutine μπορεί να σταματήσει χωρίς μπλοκάρισμα
  • Μηχανή καταστάσεων — εσωτερική αναπαράσταση της συνάρτησης suspend, όπου κάθε σημείο αναστολής είναι ξεχωριστή κατάσταση
  • Κλήση μόνο από coroutine — οι συναρτήσεις suspend μπορούν να κληθούν μόνο από άλλη συνάρτηση suspend ή από launch/async

Τι είναι το suspend function στο Kotlin;

Suspend function — είναι μια συνάρτηση δηλωμένη με τη λέξη-κλειδί suspend που μπορεί να αναστείλει την εκτέλεση σε ένα ή περισσότερα σημεία χωρίς να μπλοκάρει το νήμα. Κάθε κλήση μιας συνάρτησης suspend μέσα σε άλλη συνάρτηση suspend είναι ένα δυνητικό σημείο αναστολής.

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

Ο μεταγλωττιστής Kotlin μετατρέπει μια τέτοια συνάρτηση σε μηχανή καταστάσεων. Κάθε σημείο αναστολής (κλήση άλλης συνάρτησης suspend) γίνεται μια κατάσταση (label). Το τρέχον νήμα απελευθερώνεται μεταξύ των καταστάσεων και μετά την ολοκλήρωση της αναμενόμενης λειτουργίας, η εκτέλεση συνεχίζεται από την επόμενη κατάσταση.

Ιστορία εμφάνισης

Οι συναρτήσεις suspend εμφανίστηκαν στο Kotlin 1.3 (2018) μαζί με τα coroutines ως πειραματική λειτουργία και έγιναν σταθερές στο Kotlin 1.5 (2021). Πριν από αυτό, ο ασυγχρονισμός στο Kotlin/Java παρεχόταν μέσω callback, RxJava και CompletableFuture. Οι συναρτήσεις suspend πρόσφεραν μια εναλλακτική με γραμμική σύνταξη και αυτόματη διαχείριση νημάτων.

Πώς λειτουργούν οι συναρτήσεις suspend: Continuation και μηχανή καταστάσεων

Η κατανόηση της εσωτερικής δομής των συναρτήσεων suspend είναι το κλειδί για τη σωστή εργασία με coroutines. Σε αντίθεση με τις συνηθισμένες συναρτήσεις, κάθε συνάρτηση suspend μεταγλωττίζεται σε μια κλάση με διεπαφή Continuation.

Continuation — η κρυφή παράμετρος

Ο μεταγλωττιστής Kotlin προσθέτει μια παράμετρο τύπου Continuation στο τέλος κάθε παραμέτρου της συνάρτησης suspend. Το Continuation περιέχει:

  • context — CoroutineContext (διανομέας, job, στοιχεία περιβάλλοντος)
  • resumeWith — μέθοδος για τη συνέχιση της εκτέλεσης με αποτέλεσμα ή εξαίρεση
  • label — δείκτης της τρέχουσας κατάστασης στη μηχανή καταστάσεων

Μηχανή καταστάσεων με παράδειγμα

Ας υποθέσουμε ότι έχουμε μια συνάρτηση suspend με δύο κλήσεις σε άλλες συναρτήσεις suspend:

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

Ο μεταγλωττιστής τη μετατρέπει σε μηχανή καταστάσεων με ετικέτες:

kotlin
// Απλοποιημένη αναπαράσταση παραγόμενου κώδικα
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
        }
    }
}

Κρίσιμη παρατήρηση: αν η συνάρτηση επιστρέψει COROUTINE_SUSPENDED, το τρέχον νήμα απελευθερώνεται. Όταν η ασύγχρονη λειτουργία ολοκληρωθεί, καλείται το Continuation.resumeWith και η μηχανή καταστάσεων συνεχίζει από την επόμενη ετικέτα.

Σύνταξη συναρτήσεων suspend: δήλωση και κλήση

Η δήλωση μιας συνάρτησης suspend δεν διαφέρει από μια συνηθισμένη, εκτός από τη λέξη-κλειδί suspend πριν από το fun. Υπάρχει μόνο ένας περιορισμός: μια συνάρτηση suspend μπορεί να κληθεί μόνο από coroutine ή άλλη συνάρτηση suspend.

Βασική δήλωση

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

Σε αυτό το παράδειγμα, η delay είναι επίσης μια συνάρτηση suspend που αναστέλλει το coroutine για τον καθορισμένο αριθμό χιλιοστών του δευτερολέπτου χωρίς να μπλοκάρει το νήμα. Μετά την καθυστέρηση, η εκτέλεση συνεχίζεται.

Κλήση από coroutine

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

Το runBlocking δημιουργεί μια γέφυρα μεταξύ του συνηθισμένου κόσμου και των coroutines. Μέσα στο lambda, επιτρέπεται η κλήση οποιασδήποτε συνάρτησης suspend.

Suspend lambdas και συναρτησιακοί τύποι

Το Kotlin υποστηρίζει εκδόσεις suspend των συναρτησιακών τύπων — suspend () -> T και suspend (A) -> B. Αυτό επιτρέπει τη μετάδοση ασύγχρονων lambda σε συναρτήσεις ανώτερης τάξης:

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

Η συνάρτηση withRetry δέχεται ένα suspend lambda και επαναλαμβάνει την εκτέλεσή του σε περίπτωση σφαλμάτων. Αυτό είναι ένα τυπικό μοτίβο για αιτήματα δικτύου με επαναλήψεις.

Πώς διαφέρουν οι συναρτήσεις suspend από τις συνηθισμένες

Οι διαφορές μεταξύ των συναρτήσεων suspend και των συνηθισμένων υπερβαίνουν την απλή προσθήκη ενός τροποποιητή. Ας εξετάσουμε τις θεμελιώδεις διαφορές.

ΧαρακτηριστικόΣυνηθισμένη συνάρτησηSuspend συνάρτηση
Νήμα εκτέλεσηςΜπλοκάρει το νήμα μέχρι την ολοκλήρωσηΜπορεί να απελευθερώσει το νήμα και να συνεχίσει αργότερα
Παράμετροι μεταγλωττιστήΜόνο οι καθορισμένες παράμετροιΣιωπηρό Continuation στο τέλος
Κλήση από συνηθισμένη συνάρτησηΝαιΌχι
ΣτοίβαΦυσική στοίβα νήματοςΜηχανή καταστάσεων στο heap + φυσική στοίβα μεταξύ σημείων
ΕπιστροφήΆμεση τιμήΤιμή ή COROUTINE_SUSPENDED
ΑπόδοσηΕλάχιστο επιπλέον κόστος~μερικά νανοδευτερόλεπτα για μηχανή καταστάσεων (Kotlin 1.9+)

Γιατί οι συναρτήσεις suspend δεν μπορούν να κληθούν από συνηθισμένες

Μια συνηθισμένη συνάρτηση δεν έχει Continuation — δεν έχει πού να αποθηκεύσει την κατάσταση και με τι να συνεχίσει την εκτέλεση. Αν χρειάζεται να καλέσετε μια συνάρτηση suspend από μια συνηθισμένη, χρησιμοποιήστε το runBlocking (για δοκιμές) ή το CoroutineScope.launch (για παραγωγή λαμβάνοντας υπόψη τον κύκλο ζωής).

Παραδείγματα συναρτήσεων suspend στο Android

Ας εξετάσουμε τρία πραγματικά σενάρια χρήσης συναρτήσεων suspend σε εφαρμογές Android με Kotlin.

Παράδειγμα 1: Room DAO με suspend ερωτήματα

Το Room υποστηρίζει απευθείας τις συναρτήσεις suspend — το ερώτημα εκτελείται αυτόματα στο παρασκήνιο:

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

    @Insert
    suspend fun insertUser(user: User)
}

Το Room χρησιμοποιεί εσωτερικά το Dispatchers.IO για την εκτέλεση του ερωτήματος και το αποτέλεσμα επιστρέφεται στον διανομέα όπου κλήθηκε η συνάρτηση suspend.

Παράδειγμα 2: Σύνθεση συναρτήσεων suspend για φόρτωση οθόνης

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

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

Το ViewModelScope.launch δημιουργεί ένα coroutine μέσα στο οποίο καλείται η συνάρτηση suspend getProfile. Μετά τη λήψη του αποτελέσματος, το UI ενημερώνεται στο κύριο νήμα.

Παράδειγμα 3: Διαδοχικά ασύγχρονα βήματα

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

Τρεις συναρτήσεις suspend εκτελούνται διαδοχικά. Σε κάθε βήμα, το coroutine μπορεί να σταματήσει χωρίς να μπλοκάρει το νήμα. Αν κάποιο βήμα ρίξει εξαίρεση — τα υπόλοιπα δεν εκτελούνται, προστατεύοντας από εσφαλμένες καταστάσεις παραγγελίας.

Συνηθισμένα λάθη κατά την εργασία με συναρτήσεις suspend

Ακόμα και έμπειροι προγραμματιστές Kotlin κάνουν λάθη κατά τον σχεδιασμό συναρτήσεων suspend. Ας δούμε τα πιο συνηθισμένα.

Λάθος 1: Μπλοκάρισμα κλήσεων μέσα σε suspend

Η συνάρτηση suspend δεν καθιστά τον κώδικα αυτόματα ασύγχρονο. Τα Thread.sleep(), InputStream.read() και άλλες μπλοκάρισμα κλήσεις θα μπλοκάρουν και πάλι το νήμα. Χρησιμοποιήστε το withContext(Dispatchers.IO) για να τυλίξετε τις μπλοκάρισμα λειτουργίες.

Λάθος 2: Δημιουργία συναρτήσεων suspend χωρίς ανάγκη

Αν μια συνάρτηση δεν καλεί άλλες συναρτήσεις suspend και δεν εκτελεί ασύγχρονες λειτουργίες — ο τροποποιητής suspend είναι περιττός. Προσθέτει επιπλέον κόστος στη μηχανή καταστάσεων και περιορίζει το περιβάλλον κλήσης. Κάντε μια συνάρτηση suspend μόνο όταν πραγματικά αναστέλλεται.

Λάθος 3: Αγνόηση του CancellationException

Κατά την ακύρωση του coroutine, οι συναρτήσεις suspend ρίχνουν CancellationException. Μην το πιάνετε αλόγιστα — στερείτε από τον καλούντα κώδικα τη δυνατότητα να ολοκληρώσει σωστά την ακύρωση. Αν χρειάζεται να εκτελέσετε μια λειτουργία ολοκλήρωσης, χρησιμοποιήστε το μπλοκ finally και το NonCancellable.

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

Το μπλοκ finally εκτελείται πάντα, συμπεριλαμβανομένης της ακύρωσης, και το NonCancellable εγγυάται ότι ο καθαρισμός δεν θα διακοπεί.

Λάθος 4: Κλήση συναρτήσεων suspend από callback

Δεν μπορείτε να καλέσετε μια συνάρτηση suspend απευθείας από ένα callback χωρίς να δημιουργήσετε coroutine. Χρησιμοποιήστε το suspendCoroutine ή το suspendCancellableCoroutine για να προσαρμόσετε το στυλ callback στα coroutines.

Συχνές Ερωτήσεις

Μπορεί μια συνάρτηση suspend να μην περιέχει σημεία αναστολής;

Ναι, τεχνικά μια συνάρτηση suspend μπορεί να μην καλεί άλλες συναρτήσεις suspend. Ο μεταγλωττιστής θα δημιουργήσει μια μηχανή καταστάσεων με μία κατάσταση (label 0). Ωστόσο, μια τέτοια συνάρτηση δεν έχει πρακτική χρησιμότητα — εκτελείται σαν συνηθισμένη, αλλά με επιπλέον κόστος. Μην χρησιμοποιείτε το suspend χωρίς ανάγκη.

Πώς γίνεται ο εντοπισμός σφαλμάτων σε συναρτήσεις suspend;

Το Kotlin παρέχει τη βιβλιοθήκη kotlinx-coroutines-debug — με DebugProbes και εργαλεία ανίχνευσης coroutines. Στο Android Studio από την έκδοση Arctic Fox, υπάρχει μια ενσωματωμένη καρτέλα Coroutines στο Debugger που εμφανίζει τα ενεργά coroutines, την κατάσταση και τα σημεία αναστολής τους.

Επηρεάζει ο αριθμός των suspend σημείων την απόδοση;

Κάθε σημείο αναστολής δημιουργεί μια νέα κατάσταση στη μηχανή καταστάσεων. Για τις περισσότερες εφαρμογές, το επιπλέον κόστος ενός σημείου είναι μονάδες νανοδευτερολέπτων (Kotlin 1.9+). Μόνο όταν υπάρχουν δεκάδες χιλιάδες σημεία σε έναν βρόχο, αξίζει να συνδυάσετε λειτουργίες ή να χρησιμοποιήσετε sequence/flow.

Πώς διαφέρει η συνάρτηση suspend από το async/await σε άλλες γλώσσες;

Στο Kotlin, το suspend είναι τροποποιητής του τύπου συνάρτησης, όχι δείκτης της επιστρεφόμενης τιμής (όπως το async στη C#). Οποιαδήποτε συνάρτηση suspend μπορεί να έχει οποιεσδήποτε παραμέτρους και τύπο επιστροφής, και η κλήση της συντακτικά δεν διαφέρει από την κλήση μιας συνηθισμένης συνάρτησης — δεν υπάρχει τελεστής await στο σημείο κλήσης.

Πώς να μετατρέψετε μια συνάρτηση callback σε suspend;

Χρησιμοποιήστε το suspendCancellableCoroutine για προσαρμογή. Μέσα σε αυτό, περνάτε την εγγραφή callback που καλεί το continuation.resume() και επιστρέφετε ένα διακριτικό ακύρωσης αν το callback υποστηρίζει διαγραφή συνδρομής. Αυτό είναι το τυπικό μοτίβο για την ενσωμάτωση παλαιών Android API.

Σύνοψη

  • Suspend function — συνάρτηση με τον τροποποιητή suspend που μπορεί να αναστείλει την εκτέλεση χωρίς να μπλοκάρει το νήμα μέσω του μηχανισμού Continuation
  • Μηχανή καταστάσεων — εσωτερική αναπαράσταση της συνάρτησης suspend σε bytecode Kotlin, όπου κάθε σημείο αναστολής είναι ξεχωριστή κατάσταση με label
  • Continuation — κρυφή παράμετρος που περιέχει το περιβάλλον coroutine και τη μέθοδο resumeWith για τη συνέχιση της εκτέλεσης
  • Κλήση μόνο από coroutine — οι συναρτήσεις suspend δεν είναι προσβάσιμες από συνηθισμένες συναρτήσεις χωρίς runBlocking ή CoroutineScope
  • Μπλοκάρισμα λειτουργίες μέσα σε suspend απαιτούν withContext(Dispatchers.IO) — διαφορετικά το νήμα μπλοκάρεται
  • Room και Retrofit υποστηρίζουν εγγενώς τις συναρτήσεις suspend, διαχειριζόμενα αυτόματα τα νήματα παρασκηνίου
  • CancellationException — χειριστείτε την ακύρωση μέσω finally + NonCancellable, μην πιάνετε το CancellationException αλόγιστα

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης