Coroutines — mga pangunahing konsepto, Job at Dispatchers sa Kotlin

May-akda: IT Sectr Nai-publish: 2026-03-16 Oras ng pagbabasa: 8 min

Coroutines (mga korutin) ay magaang na thread ng Kotlin para sa asynchronous programming, na available sa pamamagitan ng library na kotlinx.coroutines. Ayon sa JetBrains Kotlin Documentation, 2026, ang Coroutines ay nagpapahintulot na i-pause ang pagpapatupad ng function nang hindi hinaharangan ang thread, hindi tulad ng tradisyonal na Thread. Ang mga korutin ay tumatakbo sa isang limitadong pool ng mga thread, na ginagawang libu-libong beses na mas magaan kaysa sa native na mga thread. Ang Kotlin Coroutines ay ganap na naka-integrate sa Android Jetpack, Retrofit, Room at iba pang sikat na library ng Android ecosystem.

Mga Pangunahing Punto

  • Coroutines — magaang na thread ng Kotlin para sa asynchronous code nang walang pagharang
  • Suspend function — function na kayang mag-pause at magpatuloy nang hindi hinaharangan ang thread
  • Dispatcher ay tumutukoy sa pool ng thread para sa pagpapatupad ng korutin
  • Job — deskriptor ng korutin na may suporta sa pagkansela at pagsubaybay ng estado
  • CoroutineScope ay namamahala sa life cycle ng mga korutin at pagkansela nito sa pagtatapos

Ano ang mga korutin ng Kotlin

Coroutines (mga korutin) ay isang mekanismo ng asynchronous programming sa Kotlin, na ipinatupad sa library na kotlinx.coroutines. Hindi tulad ng mga thread ng operating system, ang mga korutin ay hindi nakatali sa isang partikular na thread: maaari silang mag-pause sa isang thread at magpatuloy sa isa pa. Ang isang thread ay maaaring magsagawa ng libu-libong korutin, lumilipat sa pagitan nila nang may minimal na overhead.

Lumitaw ang mga korutin sa Kotlin 1.3 (2018) bilang isang eksperimental na feature at naging stable sa Kotlin 1.5 (2021). Ang Coroutines ay nalulutas ang problema ng callback hell katulad ng async/await, ngunit nag-aalok ng mas mayamang API: mga channel (Channel), Flow, paghawak ng exception sa hierarchy ng Job at direktang integrasyon sa Android Lifecycle.

Ayon sa JetBrains (2025), bawat korutin ay kumokonsumo ng humigit-kumulang 100 byte ng memory kumpara sa 1+ MB para sa isang native na thread. Ito ay nagpapahintulot na magpatakbo ng milyun-milyong korutin sa isang application nang walang panganib ng OutOfMemoryError. Ang gaan ng mga korutin ang gumagawa sa kanila na mas pinipiling kasangkapan para sa asynchrony sa Android.

Paano gumagana ang mga korutin sa ilalim ng hood

Bawat Kotlin korutin ay naka-compile sa isang state machine sa pamamagitan ng Continuation Passing Style (CPS). Nagdadagdag ang compiler ng nakatagong parameter na Continuation sa bawat suspend function. Ang Continuation ay naglalaman ng punto ng pagpapatuloy at lahat ng lokal na variable. Kapag nag-pause ang korutin, sine-save ng runtime ang Continuation, at kapag nagpatuloy, ibinabalik ito sa anumang available na thread mula sa pool ng Dispatcher.

Mga Suspend Function: pag-pause at pagpapatuloy

suspend — ang keyword ng Kotlin na nagmamarka ng function bilang pwedeng i-pause. Ang ganitong function ay maaari lamang tawagin mula sa ibang suspend function o mula sa isang korutin. Sa loob ng isang suspend function, maaaring tawagin ang ibang suspend function sa anumang pagkakasunod-sunod, at bawat punto ng tawag ay potensyal na punto ng pag-pause.

Simple ang mekanika: kapag ang isang suspend function ay tumawag ng ibang suspend function, ito ay nag-pause sa puntong iyon, pinalalaya ang thread. Pagkatapos makumpleto ng tinawag na function, ipinagpapatuloy ng runtime ang pagpapatupad mula sa naka-save na lokasyon. Ito ay tinatawag na cooperative cancellation — walang thread ang nahaharangan.

  • Pag-pause — pinalalaya ng korutin ang thread nang hindi ito hinaharangan
  • Pagpapatuloy — nagpapatuloy ang korutin mula sa parehong lugar kung saan ito nag-pause
  • Thread — ang korutin ay maaaring mag-pause sa thread A at magpatuloy sa thread B
  • Mga Exception — hinahawakan sa pamamagitan ng try/catch tulad ng sa synchronous code

Mahalaga: ang suspend function ay hindi asynchronous bilang default. Ang pagkakasunod-sunod ng pagpapatupad ay nananatiling sequential kung hindi ginagamit ang launch o async. Ang suspend ay nagpapahintulot lamang sa function na ma-pause nang hindi hinaharangan ang thread at maging bahagi ng konteksto ng korutin. Continuation Passing Style ay isang modelo ng compilation kung saan bawat suspend function ay tumatanggap ng nakatagong callback na Continuation, at ang compiler ay bubuo ng state machine para pamahalaan ang mga pag-pause at pagpapatuloy.

CoroutineScope at Structured Concurrency

CoroutineScope ay isang konteksto na tumutukoy sa life cycle ng mga korutin. Lahat ng korutin ay dapat na patakbuhin sa loob ng scope. Kapag kinansela ang scope (halimbawa, sa pagtatapos ng Activity), lahat ng child korutin nito ay awtomatikong kinakansela. Ito ay pumipigil sa pagtagas ng mga background task. Android Jetpack ay nagbibigay ng mga handa nang scope para sa bawat component: viewModelScope para sa ViewModel at lifecycleScope para sa Activity at Fragment, na awtomatikong kinakansela sa pagkasira ng kaukulang component.

Structured Concurrency — prinsipyong ginagarantiya na ang isang korutin ay hindi makukumpleto hangga't hindi kumpleto ang lahat ng child korutin nito. Ang hierarchy ng Job ay bumubuo ng isang puno: ang root korutin ay lumilikha ng parent job, ang mga anak ay lumikha ng child jobs. Ang pagkansela ng parent job ay kumakalat sa lahat ng anak. Structured Concurrency ang pangunahing pagkakaiba sa pagitan ng mga korutin at thread.

ScopeSaan ginagamitPagkansela
GlobalScopeTanging para sa mga daemon taskHindi awtomatikong kinakansela
viewModelScopeAndroid ViewModelSa paglilinis ng ViewModel
lifecycleScopeAndroid Activity/FragmentSa pagkasira ng lifecycle
coroutineScopeSa loob ng suspend functionSa pagkansela ng parent job

SupervisorJob para sa paghawak ng error

Ang ordinaryong Job sa error ng isang child korutin ay kinakansela ang lahat ng siblings. SupervisorJob ay eksepsyon: ang pagkabigo sa isang child korutin ay hindi nakakaapekto sa iba. Ito ay mahalaga kapag maraming independiyenteng task ang pinapatakbo nang magkatulad at ang isa ay maaaring mabigo nang hindi kinakailangang kanselahin ang iba.

Dispatchers at mga tagabuo ng korutin

Dispatchers ay tumutukoy kung saang thread pinapatakbo ang mga korutin. Dispatchers.Main — pangunahing UI thread ng Android. Dispatchers.IO — pool para sa mga blocking operation (network, disk). Dispatchers.Default — para sa CPU-intensive na mga task. Dispatchers.Unconfined — magsisimula sa kasalukuyang thread ngunit hindi ginagarantiya na mananatili dito. Ang pagpili ng tamang Dispatcher ay kritikal para sa performance: isang IO task sa Default ay haharang sa pool para sa mga komputasyon, habang ang CPU task sa IO ay lilikha ng mga hindi kinakailangang thread.

withContext — function para sa pagpapalit ng Dispatcher sa loob ng korutin. Halimbawa, ang isang suspend function na nagpa-parse ng JSON ay maaaring lumipat sa Dispatchers.Default sa panahon ng komputasyon at bumalik sa Dispatchers.Main para sa pag-update ng UI. withContext ang pinaka-ginagamit na tagabuo sa Android development.

Tatlong pangunahing tagabuo ng korutin

launch — nagpapatakbo ng korutin, nagbabalik ng Job, hindi nagbabalik ng resulta (fire-and-forget). async — nagpapatakbo ng korutin, nagbabalik ng Deferred kung saan makukuha ang resulta sa pamamagitan ng await. runBlocking — hinaharangan ang kasalukuyang thread para sa pagpapatupad ng korutin (para lamang sa mga test at main function). Pagpili ng tagabuo ay depende sa senaryo: launch angkop para sa mga event at update, async — para sa mga task na may resulta, runBlocking — para lamang sa mga test o entry point.

Mga halimbawa ng code na may korutin sa Kotlin

Tingnan natin ang tatlong praktikal na senaryo: basic na korutin na may launch, parallel na tawag na may async, at paghawak ng error na may SupervisorJob.

Pagpapatakbo ng korutin gamit ang launch

viewModelScope.launch ay nagpapatakbo ng korutin sa konteksto ng ViewModel. Sa paglilinis ng ViewModel, awtomatikong kinakansela ang korutin.

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

Mga parallel na request gamit ang async

coroutineScope na may async ay nagpapatakbo ng tatlong request nang magkatulad. Ang mga resulta ay kinokolekta sa pamamagitan ng .await(). Kung ang alinman sa mga request ay mabigo, lahat ay kinakansela.

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())
}

Paghawak ng error gamit ang SupervisorJob

SupervisorJob ay nagpapahintulot sa bawat korutin na matapos nang independiyente. Ang error sa isang request ay hindi kinakansela ang iba.

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) }
}

Korutin vs thread: paghahambing at mga senaryo

Mga Thread — primitive ng operating system. Bawat thread ay may sariling stack (~1 MB) at nangangailangan ng system call para sa paglikha at paglipat. Mga Korutin — primitive ng wika, hindi nakatali sa OS. Gumagamit sila ng Continuation para sa pag-save ng estado at lumilipat sa antas ng runtime nang walang system call.

  • Memory — thread ~1 MB, korutin ~100 byte. Pagkakaiba ng 10 000 beses
  • Paglikha — thread ~1 µs syscall, korutin ~0.01 µs sa antas ng JVM
  • Paglipat — thread ~0.1 µs (syscall), korutin ~0.001 µs (continuation)
  • Maximum — libu-libong thread vs milyun-milyong korutin sa device
  • Pagkansela — thread ay hindi maaaring kanselahin mula sa labas (tinanggal na Thread.stop), korutin ay maaaring kanselahin sa pamamagitan ng Job.cancel()

Ayon sa Google (2025), ang paggamit ng mga korutin sa halip na mga thread ay nagbabawas ng konsumo ng memory para sa mga background task sa Android application ng 90–95%. Lahat ng modernong Android library (Retrofit, Room, WorkManager) ay may built-in na suporta para sa mga korutin sa pamamagitan ng mga suspend function. Ang Ktor (HTTP client framework ng JetBrains) ay ganap ding binuo sa mga korutin, nagbibigay ng suspend-function para sa bawat request nang walang callback API. Ang Room ay sumusuporta sa mga korutin sa pamamagitan ng suspend-function sa DAO, na nagpapahintulot sa pagpapatupad ng database query nang hindi hinaharangan ang pangunahing thread.

Kailan gagamit ng thread sa halip na korutin

Ang mga thread ay nananatiling kinakailangan para sa native code sa pamamagitan ng JNI, blocking CPU-intensive na tawag nang walang limitasyon sa oras (video rendering, simulation) at sa integrasyon sa C library. Para sa lahat ng iba pa — mga korutin.

Mga Madalas Itanong

Ano ang pagkakaiba ng korutin sa thread?

Korutin — isang pwedeng i-pause na unit ng trabaho na tumatakbo sa isang umiiral na thread. Ang thread ay isang system resource na may sariling stack. Ang mga korutin ay libu-libong beses na mas magaan kaysa sa mga thread at hindi hinaharangan ang mga resource kapag nag-pause.

Ano ang Dispatchers.IO at ano ang pagkakaiba nito sa Default?

Dispatchers.IO ay para sa mga blocking I/O operation (network, file) at maaaring lumikha ng mga bagong thread kung kinakailangan. Dispatchers.Default ay may fixed-size na pool (bilang ng CPU core) para sa CPU-intensive na mga komputasyon.

Paano kanselahin ang isang tumatakbong korutin?

Job.cancel() ay kinakansela ang korutin at lahat ng mga anak nito. Para suriin ang pagkansela sa loob ng korutin, gamitin ang ensureActive() — nagtatapon ito ng CancellationException kung ang korutin ay nakansela.

Maaari bang gamitin ang mga korutin sa RxJava?

Oo — sa pamamagitan ng library na kotlinx-coroutines-rx3. Nagbibigay ito ng mga function na awaitSingle, awaitFirst at iba pa para sa conversion ng Observable/Single sa mga suspend function at pabalik sa pamamagitan ng flowable.

Ano ang Flow sa mga korutin?

Flow — isang malamig na asynchronous na daloy ng data, katulad ng RxJava Observable para sa mga korutin. Ang Flow ay naglalabas ng mga halaga nang sunud-sunod at nagtatapos sa isang exception o tagumpay. Sumusuporta sa map, filter, catch at iba pang operator.

Buod

  • Coroutines — magaang na thread ng Kotlin na may pag-pause nang walang pagharang sa pamamagitan ng Continuation Passing Style
  • suspend — keyword para sa pagmamarka ng mga function na pwedeng i-pause
  • Dispatchers namamahala ng pool ng thread: Main, IO, Default ayon sa pagkakasunod-sunod
  • CoroutineScope nagbubuklod ng life cycle ng korutin sa component (Activity, ViewModel)
  • launch nagpapatakbo ng korutin nang walang resulta, async/await — may resulta
  • Structured Concurrency ginagarantiya ang hierarchical na pagkansela ng mga child korutin
  • Korutin vs thread — ang mga korutin ay 10 000 beses na mas magaan at pamantayan para sa Android

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din