Coroutines — βασικές έννοιες, Job και Dispatchers στο Kotlin

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

Τα Coroutines (κορουτίνες) είναι ελαφριά νήματα Kotlin για ασύγχρονο προγραμματισμό, διαθέσιμα μέσω της βιβλιοθήκης kotlinx.coroutines. Σύμφωνα με το JetBrains Kotlin Documentation, 2026, τα Coroutines επιτρέπουν την αναστολή εκτέλεσης μιας συνάρτησης χωρίς αποκλεισμό του νήματος, σε αντίθεση με τα παραδοσιακά Thread. Τα κορουτίνες εκτελούνται σε μια περιορισμένη ομάδα νημάτων, καθιστώντας τα χιλιάδες φορές ελαφρύτερα από τα εγγενή νήματα. Τα Kotlin Coroutines είναι πλήρως ενσωματωμένα με τα Android Jetpack, Retrofit, Room και άλλες δημοφιλείς βιβλιοθήκες του οικοσυστήματος Android.

Κύρια σημεία

  • Coroutines — ελαφριά νήματα Kotlin για ασύγχρονο κώδικα χωρίς αποκλεισμό
  • Συνάρτηση suspend — συνάρτηση ικανή να αναστέλλεται και να συνεχίζεται χωρίς αποκλεισμό νήματος
  • Dispatcher καθορίζει την ομάδα νημάτων για την εκτέλεση του coroutine
  • Job — περιγραφέας του coroutine με υποστήριξη ακύρωσης και παρακολούθησης κατάστασης
  • CoroutineScope διαχειρίζεται τον κύκλο ζωής των coroutines και την ακύρωσή τους κατά την ολοκλήρωση

Τι είναι τα coroutines Kotlin

Coroutines (κορουτίνες) είναι ένας μηχανισμός ασύγχρονου προγραμματισμού στο Kotlin, υλοποιημένος στη βιβλιοθήκη kotlinx.coroutines. Σε αντίθεση με τα νήματα του λειτουργικού συστήματος, τα coroutines δεν είναι δεσμευμένα σε ένα συγκεκριμένο νήμα: μπορούν να ανασταλούν σε ένα νήμα και να συνεχιστούν σε άλλο. Ένα νήμα μπορεί να εκτελέσει χιλιάδες coroutines, εναλλάσσοντας μεταξύ τους με ελάχιστο επιπλέον κόστος.

Τα coroutines εμφανίστηκαν στο Kotlin 1.3 (2018) ως πειραματική λειτουργία και έγιναν σταθερά στο Kotlin 1.5 (2021). Τα Coroutines λύνουν το πρόβλημα του callback hell παρόμοια με το async/await, αλλά προσφέρουν πλουσιότερο API: κανάλια (Channel), Flow, διαχείριση εξαιρέσεων στην ιεραρχία Job και άμεση ενσωμάτωση με το Android Lifecycle.

Σύμφωνα με τη JetBrains (2025), κάθε coroutine καταναλώνει περίπου 100 byte μνήμης έναντι 1+ MB για ένα εγγενές νήμα. Αυτό επιτρέπει την εκτέλεση εκατομμυρίων coroutines σε μία εφαρμογή χωρίς κίνδυνο OutOfMemoryError. Ακριβώς η ελαφρότητα των coroutines τα καθιστά το προτιμώμενο εργαλείο για ασυγχρονισμό στο Android.

Πώς λειτουργούν τα coroutines κάτω από το καπό

Κάθε coroutine Kotlin μεταγλωττίζεται σε μια μηχανή καταστάσεων μέσω Continuation Passing Style (CPS). Ο μεταγλωττιστής προσθέτει μια κρυφή παράμετρο Continuation σε κάθε συνάρτηση suspend. Το Continuation περιέχει το σημείο συνέχισης και όλες τις τοπικές μεταβλητές. Όταν το coroutine αναστέλλεται, το runtime αποθηκεύει το Continuation, και όταν συνεχίζεται, το επαναφέρει σε οποιοδήποτε διαθέσιμο νήμα από την ομάδα του Dispatcher.

Συναρτήσεις Suspend: αναστολή και συνέχιση

suspend — η λέξη-κλειδί του Kotlin που χαρακτηρίζει μια συνάρτηση ως αναστέλλιμη. Μια τέτοια συνάρτηση μπορεί να κληθεί μόνο από άλλη συνάρτηση suspend ή από coroutine. Μέσα σε μια συνάρτηση suspend μπορούν να κληθούν άλλες συναρτήσεις suspend με οποιαδήποτε σειρά, και κάθε σημείο κλήσης είναι ένα δυνητικό σημείο αναστολής.

Η μηχανική είναι απλή: όταν μια συνάρτηση suspend καλεί μια άλλη συνάρτηση suspend, αναστέλλεται σε εκείνο το σημείο, ελευθερώνοντας το νήμα. Μετά την ολοκλήρωση της καλούμενης συνάρτησης, το runtime συνεχίζει την εκτέλεση από την αποθηκευμένη θέση. Αυτό ονομάζεται cooperative cancellation — κανένα νήμα δεν μπλοκάρεται.

  • Αναστολή — το coroutine ελευθερώνει το νήμα χωρίς να το μπλοκάρει
  • Συνέχιση — το coroutine συνεχίζει από το ίδιο σημείο όπου αναστάλθηκε
  • Νήμα — το coroutine μπορεί να ανασταλεί στο νήμα Α και να συνεχιστεί στο νήμα Β
  • Εξαιρέσεις — διαχειρίζονται μέσω try/catch όπως στον σύγχρονο κώδικα

Σημαντικό: η συνάρτηση suspend δεν είναι ασύγχρονη από προεπιλογή. Η σειρά εκτέλεσης παραμένει σειριακή εάν δεν χρησιμοποιούνται launch ή async. Το suspend επιτρέπει απλώς στη συνάρτηση να ανασταλεί χωρίς να μπλοκάρει το νήμα και να αποτελεί μέρος του πλαισίου coroutine. Το Continuation Passing Style είναι ένα μοντέλο μεταγλώττισης στο οποίο κάθε συνάρτηση suspend λαμβάνει μια κρυφή callback Continuation και ο μεταγλωττιστής δημιουργεί μια μηχανή καταστάσεων για τη διαχείριση αναστολών και συνεχίσεων.

CoroutineScope και Structured Concurrency

CoroutineScope είναι ένα πλαίσιο που καθορίζει τον κύκλο ζωής των coroutines. Όλα τα coroutines πρέπει να εκκινούνται μέσα σε ένα scope. Όταν το scope ακυρώνεται (π.χ. κατά την ολοκλήρωση μιας Activity), όλα τα θυγατρικά coroutines ακυρώνονται αυτόματα. Αυτό αποτρέπει διαρροές εργασιών παρασκηνίου. Το Android Jetpack παρέχει έτοιμα scopes για κάθε component: viewModelScope για ViewModel και lifecycleScope για Activity και Fragment, τα οποία ακυρώνονται αυτόματα κατά την καταστροφή του αντίστοιχου component.

Structured Concurrency — η αρχή που εγγυάται ότι ένα coroutine δεν θα ολοκληρωθεί έως ότου ολοκληρωθούν όλα τα θυγατρικά του coroutines. Η ιεραρχία Job σχηματίζει ένα δέντρο: το coroutine ρίζας δημιουργεί ένα parent job, τα παιδιά δημιουργούν child jobs. Η ακύρωση του parent job διαδίδεται σε όλα τα παιδιά. Το Structured Concurrency είναι η θεμελιώδης διαφορά μεταξύ coroutines και νημάτων.

ScopeΠού χρησιμοποιείταιΑκύρωση
GlobalScopeΜόνο για εργασίες daemonΔεν ακυρώνεται αυτόματα
viewModelScopeAndroid ViewModelΚατά τον καθαρισμό ViewModel
lifecycleScopeAndroid Activity/FragmentΚατά την καταστροφή lifecycle
coroutineScopeΜέσα σε συνάρτηση suspendΚατά την ακύρωση του parent job

SupervisorJob για διαχείριση σφαλμάτων

Το συνηθισμένο Job σε σφάλμα ενός θυγατρικού coroutine ακυρώνει όλα τα siblings. Το SupervisorJob αποτελεί εξαίρεση: μια αποτυχία σε ένα θυγατρικό coroutine δεν επηρεάζει τα υπόλοιπα. Αυτό είναι σημαντικό όταν πολλές ανεξάρτητες εργασίες εκτελούνται παράλληλα και μία μπορεί να αποτύχει χωρίς να χρειαστεί να ακυρωθούν οι άλλες.

Dispatchers και δημιουργοί coroutines

Dispatchers καθορίζουν σε ποια νήματα εκτελούνται τα coroutines. Dispatchers.Main — το κύριο νήμα UI του Android. Dispatchers.IO — ομάδα για λειτουργίες αποκλεισμού (δίκτυο, δίσκος). Dispatchers.Default — για εργασίες έντασης CPU. Dispatchers.Unconfined — ξεκινά στο τρέχον νήμα αλλά δεν εγγυάται παραμονή σε αυτό. Η επιλογή του σωστού Dispatcher είναι κρίσιμη για την απόδοση: μια εργασία IO στο Default θα μπλοκάρει την ομάδα για υπολογισμούς, ενώ μια εργασία CPU στο IO θα δημιουργήσει περιττά νήματα.

withContext — συνάρτηση για εναλλαγή Dispatcher μέσα στο coroutine. Για παράδειγμα, μια συνάρτηση suspend που αναλύει JSON μπορεί να αλλάξει σε Dispatchers.Default κατά τον υπολογισμό και να επιστρέψει σε Dispatchers.Main για ενημέρωση UI. Το withContext είναι ο πιο χρησιμοποιούμενος δημιουργός στην ανάπτυξη Android.

Τρεις κύριοι δημιουργοί coroutines

launch — εκκινεί ένα coroutine, επιστρέφει Job, δεν επιστρέφει αποτέλεσμα (fire-and-forget). async — εκκινεί ένα coroutine, επιστρέφει Deferred από το οποίο μπορεί να ληφθεί το αποτέλεσμα μέσω await. runBlocking — μπλοκάρει το τρέχον νήμα για την εκτέλεση του coroutine (μόνο για δοκιμές και main συναρτήσεις). Επιλογή δημιουργού εξαρτάται από το σενάριο: το launch είναι κατάλληλο για γεγονότα και ενημερώσεις, το async για εργασίες με αποτέλεσμα, το runBlocking μόνο για δοκιμές ή σημεία εισόδου.

Παραδείγματα κώδικα με coroutines στο Kotlin

Ας εξετάσουμε τρία πρακτικά σενάρια: βασικό coroutine με launch, παράλληλη κλήση με async και διαχείριση σφαλμάτων με SupervisorJob.

Εκκίνηση coroutine με launch

viewModelScope.launch εκκινεί ένα coroutine στο πλαίσιο του ViewModel. Κατά τον καθαρισμό του ViewModel, το coroutine ακυρώνεται αυτόματα.

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

Παράλληλα αιτήματα με async

coroutineScope με async εκκινεί τρία αιτήματα παράλληλα. Τα αποτελέσματα συλλέγονται μέσω .await(). Εάν οποιοδήποτε αίτημα αποτύχει, όλα ακυρώνονται.

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

Διαχείριση σφαλμάτων με SupervisorJob

SupervisorJob επιτρέπει σε κάθε coroutine να ολοκληρωθεί ανεξάρτητα. Ένα σφάλμα σε ένα αίτημα δεν ακυρώνει τα υπόλοιπα.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

Coroutines vs νήματα: σύγκριση και σενάρια

Νήματα (Thread) — πρωτόγονο του λειτουργικού συστήματος. Κάθε νήμα έχει τη δική του στοίβα (~1 MB) και απαιτεί κλήση συστήματος για δημιουργία και εναλλαγή. Coroutines — πρωτόγονο γλώσσας, μη δεσμευμένο στο OS. Χρησιμοποιούν Continuation για αποθήκευση κατάστασης και εναλλάσσονται σε επίπεδο runtime χωρίς κλήσεις συστήματος.

  • Μνήμη — νήμα ~1 MB, coroutine ~100 byte. Διαφορά 10 000 φορές
  • Δημιουργία — νήμα ~1 µs syscall, coroutine ~0.01 µs σε επίπεδο JVM
  • Εναλλαγή — νήμα ~0.1 µs (syscall), coroutine ~0.001 µs (continuation)
  • Μέγιστο — χιλιάδες νήματα vs εκατομμύρια coroutines στη συσκευή
  • Ακύρωση — το νήμα δεν μπορεί να ακυρωθεί εξωτερικά (καταργημένο Thread.stop), το coroutine μπορεί μέσω Job.cancel()

Σύμφωνα με την Google (2025), η χρήση coroutines αντί για νήματα μειώνει την κατανάλωση μνήμης για εργασίες παρασκηνίου σε εφαρμογές Android κατά 90–95%. Όλες οι σύγχρονες βιβλιοθήκες Android (Retrofit, Room, WorkManager) έχουν ενσωματωμένη υποστήριξη για coroutines μέσω συναρτήσεων suspend. Το Ktor (το πλαίσιο HTTP πελάτη της JetBrains) είναι επίσης πλήρως χτισμένο σε coroutines, παρέχοντας συναρτήσεις-suspend για κάθε αίτημα χωρίς callback API. Το Room υποστηρίζει coroutines μέσω συναρτήσεων-suspend στο DAO, επιτρέποντας την εκτέλεση ερωτημάτων βάσης δεδομένων χωρίς αποκλεισμό του κύριου νήματος.

Πότε να χρησιμοποιείτε νήματα αντί για coroutines

Τα νήματα παραμένουν απαραίτητα για εγγενή κώδικα μέσω JNI, κλήσεις αποκλεισμού έντασης CPU χωρίς χρονικό περιορισμό (απόδοση βίντεο, προσομοιώσεις) και κατά την ενσωμάτωση με βιβλιοθήκες C. Για οτιδήποτε άλλο — coroutines.

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

Σε τι διαφέρει το coroutine από το νήμα;

Coroutine — μια αναστέλλιμη μονάδα εργασίας που εκτελείται σε ένα υπάρχον νήμα. Το νήμα είναι ένας πόρος συστήματος με δική του στοίβα. Τα coroutines είναι χιλιάδες φορές ελαφρύτερα από τα νήματα και δεν μπλοκάρουν πόρους κατά την αναστολή.

Τι είναι το Dispatchers.IO και σε τι διαφέρει από το Default;

Dispatchers.IO προορίζεται για λειτουργίες I/O αποκλεισμού (δίκτυο, αρχεία) και μπορεί να δημιουργεί νέα νήματα όταν χρειάζεται. Dispatchers.Default έχει σταθερή ομάδα (αριθμός πυρήνων CPU) για υπολογισμούς έντασης CPU.

Πώς ακυρώνω ένα coroutine που εκτελείται;

Job.cancel() ακυρώνει το coroutine και όλα τα παιδιά του. Για έλεγχο ακύρωσης μέσα στο coroutine, χρησιμοποιήστε ensureActive() — πετάει CancellationException εάν το coroutine έχει ακυρωθεί.

Μπορώ να χρησιμοποιήσω coroutines με RxJava;

Ναι — μέσω της βιβλιοθήκης kotlinx-coroutines-rx3. Παρέχει συναρτήσεις awaitSingle, awaitFirst και άλλες για μετατροπή Observable/Single σε συναρτήσεις suspend και αντίστροφα μέσω flowable.

Τι είναι το Flow στα coroutines;

Flow — μια ψυχρή ασύγχρονη ροή δεδομένων, το αντίστοιχο του RxJava Observable για coroutines. Το Flow εκπέμπει τιμές σειριακά και τελειώνει με εξαίρεση ή επιτυχία. Υποστηρίζει τους τελεστές map, filter, catch και άλλους.

Σύνοψη

  • Coroutines — ελαφριά νήματα Kotlin με αναστολή χωρίς αποκλεισμό μέσω Continuation Passing Style
  • suspend — λέξη-κλειδί για τη σήμανση αναστέλλιμων συναρτήσεων
  • Dispatchers διαχειρίζονται την ομάδα νημάτων: Main, IO, Default αντίστοιχα
  • CoroutineScope συνδέει τον κύκλο ζωής των coroutines με το component (Activity, ViewModel)
  • launch εκκινεί coroutine χωρίς αποτέλεσμα, async/await — με αποτέλεσμα
  • Structured Concurrency εγγυάται ιεραρχική ακύρωση θυγατρικών coroutines
  • Coroutines vs νήματα — τα coroutines είναι 10 000 φορές ελαφρύτερα και αποτελούν πρότυπο για Android

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

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

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

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