Dispatchers — kulcsfogalmak, diszpécser típusok és működésük

Szerző: IT Sectr Megjelenés: 2026-06-22 Olvasási idő: 9 perc

Dispatchers a Kotlin Coroutines-ben — a CoroutineContext komponensei, amelyek meghatározzák a korutinok végrehajtásához használt szálakat: Main (UI-szál), IO (hálózat és lemez), Default (CPU-intenzív feladatok) és Unconfined (aktuális szál). Minden diszpécser egy specializált szálkészletet kezel, amely az adott munkatípushoz van optimalizálva. A JetBrains, 2024 útmutatója szerint a megfelelő diszpécser kiválasztása kritikus fontosságú az alkalmazás teljesítménye és stabilitása szempontjából.

Főbb pontok

  • Dispatchers — előre meghatározott korutin diszpécserek, amelyek a feladatok szálak közötti elosztását kezelik
  • Dispatchers.Main — Android UI-szál, a felület frissítéséhez és a View-val való munkához
  • Dispatchers.IO — készlet hálózati kérésekhez, fájlok olvasásához/írásához és adatbázisokhoz (akár 64 szál)
  • Dispatchers.Default — készlet CPU-intenzív feladatokhoz a processzormagok száma alapján
  • Dispatchers.Unconfined — az aktuális szál öröklése, váltás nélkül

Mik azok a Dispatchers?

Dispatchers — a CoroutineDispatcher interfész implementációi, amelyek a CoroutineContext elemei. Meghatározzák, hogy melyik szálon vagy szálkészleten hajtódik végre a korutin. Korutin launch vagy async segítségével történő létrehozásakor a diszpécser első paraméterként adható át: launch(Dispatchers.IO) { ... }. Ha nincs diszpécser megadva, a külső CoroutineScope-ból öröklődik.

A Kotlin négy beépített diszpécsert kínál: Main, IO, Default, Unconfined. Minden diszpécser saját, az adott művelettípushoz optimalizált szálkészletet használ. A diszpécser helyes megválasztása határozza meg az alkalmazás teljesítményét: a rossz választás a felület lassulásához, a CPU-magok kihasználatlanságához vagy a szálak nem hatékony felhasználásához vezet.

DiszpécserSzálkészletMax. szálakHasználat
Dispatchers.MainEgy (UI)1UI frissítés, LiveData, View
Dispatchers.IOIO készlet64 (limitedParallelism)Hálózat, fájlok, adatbázisok
Dispatchers.DefaultCPU készletN magRendezés, elemzés, számítások
Dispatchers.UnconfinedAktuális szálN/AKözbenső műveletek, tesztek

Dispatchers.Main: UI-szál

Dispatchers.Main — a korutinokat az Android főszálán végrehajtó diszpécser. A felülettel kapcsolatos műveletekre szolgál: TextView frissítése, notifyDataSetChanged meghívása, LiveData és StateFlow használata. Androidban ez a diszpécser Handleren (Looper.getMainLooper()) keresztül van implementálva.

kotlin
// Helyes átváltás Main-re UI frissítésekhez
viewModelScope.launch(Dispatchers.IO) {
    val data = repository.fetchData()
    withContext(Dispatchers.Main) {
        _uiState.value = data
    }
}

Ha a korutin már a Main-diszpécseren van, a további withContext(Dispatchers.Main) nem okoz többletterhelést — a diszpécser ellenőrzi az aktuális szálat és kihagyja a váltást. withContext az előnyben részesített mód a diszpécserek közötti váltásra.

Dispatchers.IO: hálózat és lemezműveletek

Dispatchers.IO — bemeneti-kimeneti műveletekre optimalizált diszpécser: HTTP-kérések (Ktor, OkHttp), fájlok olvasása és írása, Room vagy SQLDelight használata. Alapértelmezés szerint 64 szálból álló készletet használ, ami terhelés alatt skálázható. Minden új IO-kérés létrehozhat egy további szálat a határ eléréséig.

Párhuzamosság korlátozása

Az egyidejű IO-műveletek számának szabályozásához használja a limitedParallelism() függvényt. Ez a függvény egy új diszpécsert hoz létre a párhuzamos szálak számának korlátozásával, megakadályozva a készlet kimerülését tömeges műveletek esetén.

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

// 100 fájl betöltése 4 egyidejű művelet korláttal
coroutineScope {
    val files = (1..100).map { index ->
        async(limitedIo) {
            downloadFile("file_$index")
        }
    }
    files.awaitAll()
}

Használja az IO-diszpécsert minden olyan művelethez, ahol a korutin várakozással tölti az időt (I/O-bound). A CPU-intenzív feladatok az IO-diszpécseren nem hatékonyak — olyan szálakat foglalnak le, amelyek a bemenet-kimenet számára lettek fenntartva, csökkentve a rendszer átviteli sebességét.

Dispatchers.Default: CPU-intenzív feladatok

Dispatchers.Default — a processzort terhelő számítási műveletekhez való diszpécser: rendezés, szűrés, JSON elemzés (Moshi, Kotlinx Serialization), képfeldolgozás, számítások. A készlet mérete megegyezik a processzormagok számával (de legalább 2). Ez biztosítja a CPU maximális terhelését kontextusváltás nélkül.

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

Ne használja a Dispatchers.Default-ot IO-műveletekhez — ez blokkolja a CPU-készlet azon szálait, amelyek számítási feladatokat dolgozhatnának fel. Az IO és Default szétválasztása lehetővé teszi a rendszererőforrások optimális kihasználását: az IO-szálak a bemenet-kimenetre várnak, a CPU-szálak folyamatosan számításokkal vannak elfoglalva.

Dispatchers.Unconfined: aktuális szál

Dispatchers.Unconfined — egy speciális diszpécser, amely nem köti a korutint egyetlen készlethez sem. A korutin ugyanabban a szálban kezdi meg a végrehajtást, ahol a launch/async meghívásra került, és felfüggesztés után abban a szálban folytatódik, amely a resume-ot hívta. Ez a viselkedés olyan közbenső műveletekhez alkalmas, amelyek nem igényelnek rögzített kontextust.

kotlin
fun main() = runBlocking {
    launch(Dispatchers.Unconfined) {
        println("Késleltetés előtt: ${Thread.currentThread().getName()}")
        delay(500L)
        println("Késleltetés után: ${Thread.currentThread().getName()}")
    }
}

Production kódban a Dispatchers.Unconfined ritkán használatos. Fő esetek: könnyű transzformációk az adatok másik diszpécsernek való továbbítása előtt, valamint tesztek. Production terheléshez használjon explicit diszpécsereket — az Unconfined kiszámíthatatlan, mivel a végrehajtás szálja a resume implementációjától függ.

Hogyan válasszunk diszpécsert

A diszpécser kiválasztását a feladat típusa határozza meg: UI műveletek → Main, I/O-bound → IO, CPU-bound → Default, közbenső → öröklés a scope-ból. Android esetén ajánlott a korutint azon a diszpécseren indítani, ahol a fő munka történik, és a UI frissítése előtt withContext segítségével Main-re váltani.

  • Ne futtasson IO műveleteket a Main-diszpécseren — ez blokkolja a UI-t
  • Ne futtasson CPU-intenzív feladatokat az IO-diszpécseren — ez nem hatékonyan használja az IO-készlet szálait
  • Használja a limitedParallelism függvényt a párhuzamosság szabályozására tömeges IO műveleteknél
  • Váltson diszpécsert a withContext segítségével, ne új scope létrehozásával
  • Örökölje a diszpécsert a scope-ból, ha a korutin nem igényel specifikus készletet

Összetett forgatókönyvekhez kombinálja a diszpécsereket a + operátorral: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. Ez egy CoroutineContext-et hoz létre a megadott diszpécserrel, hibakezeléssel és izolált Job-hierarchiával.

Gyakran Ismételt Kérdések

Miben különbözik a Dispatchers.IO és a Dispatchers.Default?

Dispatchers.IO akár 64 szálas készletet használ az I/O-bound műveletekhez (bemenet-kimenetre várás), míg Dispatchers.Default a CPU-magok számának megfelelő készletet a számítási feladatokhoz. Szálhiány esetén a két készlet megoszthatja egymással a szálakat.

Létrehozhatok saját diszpécsert a Kotlin Coroutines-ben?

Igen, használja a newSingleThreadContext() függvényt egyszálú vagy a newFixedThreadPoolContext() függvényt fix készlethez. Production esetén alkalmazza a limitedParallelism() függvényt meglévő diszpécserek alapján — ez hatékonyabb, mint új készletek létrehozása.

Mi történik, ha a Dispatchers.Main-t háttérszálon hívják?

Ha a Dispatchers.Main nem érhető el (pl. JUnit tesztben vagy háttérszolgáltatásban), IllegalStateException dobódik. Tesztekhez használja a TestCoroutineDispatcher-t, háttérszolgáltatásokhoz a Dispatchers.IO vagy Default értéket.

Hogyan korlátozhatom a párhuzamos IO műveletek számát?

Használja a Dispatchers.IO.limitedParallelism(N) függvényt, ahol N a maximális párhuzamos szálak száma. Ez megakadályozza a készlet kimerülését tömeges kérések esetén és ellenőrzött párhuzamosságot biztosít.

Mikor használjam a Dispatchers.Unconfined-et?

Dispatchers.Unconfined közbenső műveletekhez alkalmas: könnyű adat-transzformációk másik diszpécsernek való továbbítás előtt, tesztforgatókönyvek. Android production kódban nem ajánlott a felfüggesztés utáni bizonytalan végrehajtási szál miatt.

Összefoglalás

  • Dispatchers — a korutinok végrehajtási szálait meghatározó CoroutineContext komponensek
  • Dispatchers.Main — Android UI műveletekhez, egy főszál
  • Dispatchers.IO — hálózati és lemezműveletekhez, akár 64 szálas készlet
  • Dispatchers.Default — CPU-intenzív számításokhoz, készlet a magok számának megfelelően
  • Dispatchers.Unconfined — szálhoz nem kötött, közbenső műveletekhez
  • withContext — a fő mechanizmus a diszpécserek közötti váltásra a korutinon belül
  • A rossz diszpécser választás UI lassuláshoz vagy az erőforrások nem hatékony használatához vezet

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is