Dispatchers — konsep kunci, tipe dispatcher dan cara kerjanya

Penulis: IT Sectr Diterbitkan: 2026-06-22 Waktu membaca: 9 mnt

Dispatchers di Kotlin Coroutines — komponen CoroutineContext yang menentukan thread untuk mengeksekusi coroutine: Main (thread UI), IO (jaringan dan disk), Default (tugas intensif CPU) dan Unconfined (thread saat ini). Setiap dispatcher mengelola kumpulan thread khusus yang dioptimalkan untuk jenis pekerjaan tertentu. Menurut panduan JetBrains, 2024, pemilihan dispatcher yang tepat sangat penting untuk kinerja dan stabilitas aplikasi.

Poin Utama

  • Dispatchers — dispatcher coroutine yang telah ditentukan, mengelola distribusi tugas ke thread
  • Dispatchers.Main — thread UI Android, untuk memperbarui antarmuka dan bekerja dengan View
  • Dispatchers.IO — kumpulan untuk permintaan jaringan, membaca/menulis file dan database (hingga 64 thread)
  • Dispatchers.Default — kumpulan untuk tugas intensif CPU berdasarkan jumlah inti prosesor
  • Dispatchers.Unconfined — mewarisi thread saat ini, tanpa perpindahan

Apa itu Dispatchers?

Dispatchers — implementasi antarmuka CoroutineDispatcher, yang merupakan elemen CoroutineContext. Mereka menentukan di thread atau kumpulan thread mana coroutine akan dijalankan. Saat membuat coroutine melalui launch atau async, dispatcher dapat diberikan sebagai parameter pertama: launch(Dispatchers.IO) { ... }. Jika dispatcher tidak ditentukan, akan diwarisi dari CoroutineScope eksternal.

Kotlin menyediakan empat dispatcher bawaan: Main, IO, Default, Unconfined. Setiap dispatcher menggunakan kumpulan thread sendiri, dioptimalkan untuk jenis operasi tertentu. Pemilihan dispatcher yang tepat menentukan kinerja aplikasi: kesalahan pemilihan menyebabkan lag antarmuka, inti CPU menganggur, atau konsumsi thread yang tidak efisien.

DispatcherKumpulan threadMaks. threadPenggunaan
Dispatchers.MainSatu (UI)1Pembaruan UI, LiveData, View
Dispatchers.IOKumpulan IO64 (limitedParallelism)Jaringan, file, database
Dispatchers.DefaultKumpulan CPUN intiPengurutan, parsing, kalkulasi
Dispatchers.UnconfinedThread saat iniT/AOperasi perantara, pengujian

Dispatchers.Main: thread UI

Dispatchers.Main — dispatcher yang menjalankan coroutine di thread utama Android. Ini ditujukan untuk operasi yang terkait dengan antarmuka: memperbarui TextView, memanggil notifyDataSetChanged, bekerja dengan LiveData dan StateFlow. Di Android, dispatcher ini diimplementasikan melalui Handler (Looper.getMainLooper()).

kotlin
// Peralihan yang benar ke Main untuk pembaruan UI
viewModelScope.launch(Dispatchers.IO) {
    val data = repository.fetchData()
    withContext(Dispatchers.Main) {
        _uiState.value = data
    }
}

Jika coroutine sudah berada di Main-dispatcher, withContext(Dispatchers.Main) tambahan tidak menimbulkan overhead — dispatcher memeriksa thread saat ini dan melewatkan perpindahan. withContext adalah cara yang lebih disukai untuk berpindah antar dispatcher.

Dispatchers.IO: jaringan dan operasi disk

Dispatchers.IO — dispatcher yang dioptimalkan untuk operasi input-output: permintaan HTTP (Ktor, OkHttp), membaca dan menulis file, bekerja dengan Room atau SQLDelight. Secara default menggunakan kumpulan 64 thread, dapat diskalakan di bawah beban. Setiap permintaan IO baru dapat membuat thread tambahan hingga batas tercapai.

Membatasi paralelisme

Untuk mengontrol jumlah operasi IO simultan, gunakan limitedParallelism(). Fungsi ini membuat dispatcher baru dengan batasan jumlah thread paralel, mencegah habisnya kumpulan pada operasi massal.

kotlin
val limitedIo = Dispatchers.IO.limitedParallelism(4)

// Muat 100 file dengan batas 4 operasi bersamaan
coroutineScope {
    val files = (1..100).map { index ->
        async(limitedIo) {
            downloadFile("file_$index")
        }
    }
    files.awaitAll()
}

Gunakan IO-dispatcher untuk semua operasi di mana coroutine menghabiskan waktu menunggu (I/O-bound). Tugas intensif CPU pada IO-dispatcher tidak efisien — mereka menempati thread yang ditujukan untuk input-output, mengurangi throughput sistem.

Dispatchers.Default: tugas intensif CPU

Dispatchers.Default — dispatcher untuk operasi komputasi yang membebani prosesor: pengurutan, pemfilteran, parsing JSON (Moshi, Kotlinx Serialization), pemrosesan gambar, kalkulasi. Ukuran kumpulan sama dengan jumlah inti prosesor (tetapi tidak kurang dari 2). Ini memastikan beban CPU maksimal tanpa perpindahan konteks.

kotlin
suspend fun processData(input: List<RawRecord>): List<ProcessedRecord> {
    return withContext(Dispatchers.Default) {
        input
            .parallelStream()
            .map { transform(it) }
            .toList()
    }
}

Jangan gunakan Dispatchers.Default untuk operasi IO — ini akan memblokir thread kumpulan CPU yang bisa memproses tugas komputasi. Pemisahan menjadi IO dan Default memungkinkan pemanfaatan optimal sumber daya sistem: thread IO menunggu input-output, thread CPU terus sibuk dengan kalkulasi.

Dispatchers.Unconfined: thread saat ini

Dispatchers.Unconfined — dispatcher khusus yang tidak mengikat coroutine ke kumpulan mana pun. Coroutine memulai eksekusi di thread yang sama di mana launch/async dipanggil, dan setelah penangguhan dilanjutkan di thread yang memanggil resume. Perilaku ini cocok untuk operasi perantara yang tidak memerlukan konteks tetap.

kotlin
fun main() = runBlocking {
    launch(Dispatchers.Unconfined) {
        println("Sebelum penundaan: ${Thread.currentThread().getName()}")
        delay(500L)
        println("Setelah penundaan: ${Thread.currentThread().getName()}")
    }
}

Dalam kode produksi, Dispatchers.Unconfined jarang digunakan. Kasus utama: transformasi ringan sebelum mengirim data ke dispatcher lain dan pengujian. Untuk beban produksi, gunakan dispatcher eksplisit — Unconfined tidak dapat diprediksi karena thread eksekusi tergantung pada implementasi resume.

Cara memilih dispatcher

Pemilihan dispatcher ditentukan oleh jenis tugas: operasi UI → Main, I/O-bound → IO, CPU-bound → Default, perantara → warisan dari scope. Untuk Android, disarankan memulai coroutine pada dispatcher tempat pekerjaan utama dilakukan, dan sebelum pembaruan UI beralih ke Main melalui withContext.

  • Jangan jalankan operasi IO pada Main-dispatcher — ini memblokir UI
  • Jangan jalankan tugas intensif CPU pada IO-dispatcher — ini menghabiskan thread kumpulan IO secara tidak efisien
  • Gunakan limitedParallelism untuk mengontrol paralelisme pada operasi IO massal
  • Pindahkan dispatcher dengan withContext, bukan dengan membuat scope baru
  • Warisi dispatcher dari scope, jika coroutine tidak memerlukan kumpulan spesifik

Untuk skenario kompleks, gabungkan dispatcher dengan operator +: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. Ini membuat CoroutineContext dengan dispatcher yang ditentukan, penanganan kesalahan, dan hierarki Job yang terisolasi.

Pertanyaan Umum

Apa perbedaan antara Dispatchers.IO dan Dispatchers.Default?

Dispatchers.IO menggunakan kumpulan hingga 64 thread untuk operasi I/O-bound (menunggu input-output), dan Dispatchers.Default — kumpulan berdasarkan jumlah inti CPU untuk tugas komputasi. Saat thread tidak mencukupi, kedua kumpulan dapat berbagi thread satu sama lain.

Bisakah saya membuat dispatcher sendiri di Kotlin Coroutines?

Ya, gunakan newSingleThreadContext() untuk single-thread atau newFixedThreadPoolContext() untuk kumpulan tetap. Untuk produksi, gunakan limitedParallelism() berdasarkan dispatcher yang ada — ini lebih efisien daripada membuat kumpulan baru.

Apa yang terjadi saat memanggil Dispatchers.Main di thread latar belakang?

Jika Dispatchers.Main tidak tersedia (misalnya, dalam pengujian JUnit atau layanan latar belakang), IllegalStateException akan dilemparkan. Untuk pengujian, gunakan TestCoroutineDispatcher, untuk layanan latar belakang — Dispatchers.IO atau Default.

Bagaimana cara membatasi jumlah operasi IO paralel?

Gunakan Dispatchers.IO.limitedParallelism(N), di mana N adalah jumlah maksimum thread paralel. Ini mencegah habisnya kumpulan pada permintaan massal dan memberikan paralelisme yang terkendali.

Kapan menggunakan Dispatchers.Unconfined?

Dispatchers.Unconfined cocok untuk operasi perantara: transformasi data ringan sebelum dikirim ke dispatcher lain, skenario pengujian. Dalam kode produksi Android tidak disarankan karena thread eksekusi yang tidak pasti setelah penangguhan.

Ringkasan

  • Dispatchers — komponen CoroutineContext yang menentukan thread eksekusi coroutine
  • Dispatchers.Main — untuk operasi UI Android, satu thread utama
  • Dispatchers.IO — untuk operasi jaringan dan disk, kumpulan hingga 64 thread
  • Dispatchers.Default — untuk komputasi intensif CPU, kumpulan berdasarkan jumlah inti
  • Dispatchers.Unconfined — tanpa ikatan thread, untuk operasi perantara
  • withContext — mekanisme utama untuk berpindah antar dispatcher di dalam coroutine
  • Pemilihan dispatcher yang salah menyebabkan lag UI atau penggunaan sumber daya yang tidak efisien

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga