Dispatchers — nyckelbegrepp, typer av dispatchers och hur de fungerar

Författare: IT Sectr Publicerad: 2026-06-22 Lästid: 9 min

Dispatchers i Kotlin Coroutines — komponenter i CoroutineContext som bestämmer trådar för exekvering av korutiner: Main (UI-tråd), IO (nätverk och disk), Default (CPU-intensiva uppgifter) och Unconfined (aktuell tråd). Varje dispatcher hanterar en specialiserad trådpool optimerad för en specifik typ av arbete. Enligt JetBrains guide, 2024 är valet av rätt dispatcher avgörande för applikationens prestanda och stabilitet.

Huvudpunkter

  • Dispatchers — fördefinierade korutin-dispatchers som hanterar fördelning av uppgifter över trådar
  • Dispatchers.Main — Android UI-tråd, för att uppdatera gränssnittet och arbeta med View
  • Dispatchers.IO — pool för nätverksförfrågningar, läsning/skrivning av filer och databaser (upp till 64 trådar)
  • Dispatchers.Default — pool för CPU-intensiva uppgifter baserat på antalet processorkärnor
  • Dispatchers.Unconfined — nedärvning av aktuell tråd, utan växling

Vad är Dispatchers?

Dispatchers — implementationer av gränssnittet CoroutineDispatcher, som är element i CoroutineContext. De bestämmer på vilken tråd eller trådpool korutinen ska exekveras. När en korutin skapas via launch eller async kan dispatcher skickas som första parameter: launch(Dispatchers.IO) { ... }. Om ingen dispatcher anges ärvs den från den externa CoroutineScope.

Kotlin tillhandahåller fyra inbyggda dispatchers: Main, IO, Default, Unconfined. Varje dispatcher använder sin egen trådpool optimerad för en specifik typ av operation. Rätt val av dispatcher avgör applikationens prestanda: felaktigt val leder till fördröjningar i gränssnittet, overksamma CPU-kärnor eller ineffektiv trådförbrukning.

DispatcherTrådpoolMax trådarAnvändning
Dispatchers.MainEn (UI)1UI-uppdatering, LiveData, View
Dispatchers.IOIO-pool64 (limitedParallelism)Nätverk, filer, databaser
Dispatchers.DefaultCPU-poolN kärnorSortering, parsning, beräkningar
Dispatchers.UnconfinedAktuell trådN/AMellanliggande operationer, tester

Dispatchers.Main: UI-tråd

Dispatchers.Main — dispatcher som utför korutiner på huvudtråden i Android. Den är avsedd för operationer relaterade till gränssnittet: uppdatera TextView, anropa notifyDataSetChanged, arbeta med LiveData och StateFlow. I Android är denna dispatcher implementerad via Handler (Looper.getMainLooper()).

kotlin
// Korrekt växling till Main för UI-uppdateringar
viewModelScope.launch(Dispatchers.IO) {
    val data = repository.fetchData()
    withContext(Dispatchers.Main) {
        _uiState.value = data
    }
}

Om korutinen redan är på Main-dispatchern skapar extra withContext(Dispatchers.Main) ingen overhead — dispatchern kontrollerar den aktuella tråden och hoppar över växlingen. withContext är det föredragna sättet att växla mellan dispatchers.

Dispatchers.IO: nätverk och disklagring

Dispatchers.IO — dispatcher optimerad för in-/utmatningsoperationer: HTTP-förfrågningar (Ktor, OkHttp), läsning och skrivning av filer, arbete med Room eller SQLDelight. Den använder som standard en pool på 64 trådar, skalbar under belastning. Varje ny IO-förfrågan kan skapa en extra tråd tills gränsen nås.

Begränsa parallellism

För att kontrollera antalet samtidiga IO-operationer, använd limitedParallelism(). Denna funktion skapar en ny dispatcher med en begränsning av antalet parallella trådar, vilket förhindrar att poolen töms vid massiva operationer.

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

// Ladda 100 filer med en gräns på 4 samtidiga operationer
coroutineScope {
    val files = (1..100).map { index ->
        async(limitedIo) {
            downloadFile("file_$index")
        }
    }
    files.awaitAll()
}

Använd IO-dispatchern för alla operationer där korutinen tillbringar tid med att vänta (I/O-bound). CPU-intensiva uppgifter på IO-dispatchern är ineffektiva — de upptar trådar avsedda för in-/utmatning, vilket minskar systemets genomströmning.

Dispatchers.Default: CPU-intensiva uppgifter

Dispatchers.Default — dispatcher för beräkningsoperationer som belastar processorn: sortering, filtrering, JSON-parsning (Moshi, Kotlinx Serialization), bildbehandling, beräkningar. Poolens storlek är lika med antalet processorkärnor (men inte mindre än 2). Detta säkerställer maximal CPU-belastning utan kontextväxling.

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

Använd inte Dispatchers.Default för IO-operationer — detta blockerar trådarna i CPU-poolen som skulle kunna bearbeta beräkningsuppgifter. Uppdelningen i IO och Default möjliggör optimal användning av systemresurser: IO-trådar väntar på in-/utmatning, CPU-trådar är ständigt upptagna med beräkningar.

Dispatchers.Unconfined: aktuell tråd

Dispatchers.Unconfined — en speciell dispatcher som inte binder korutinen till någon pool. Korutinen börjar exekveras i samma tråd där launch/async anropades och återupptas efter avstängning i den tråd som anropade resume. Detta beteende är lämpligt för mellanliggande operationer som inte kräver en fast kontext.

kotlin
fun main() = runBlocking {
    launch(Dispatchers.Unconfined) {
        println("Före fördröjning: ${Thread.currentThread().getName()}")
        delay(500L)
        println("Efter fördröjning: ${Thread.currentThread().getName()}")
    }
}

I produktionskod används Dispatchers.Unconfined sällan. Huvudfall: lätta transformationer innan data skickas till en annan dispatcher och tester. För produktionsbelastning, använd explicita dispatchers — Unconfined är oförutsägbar eftersom exekveringstråden beror på implementeringen av resume.

Hur man väljer dispatcher

Valet av dispatcher bestäms av uppgiftstypen: UI-operationer → Main, I/O-bound → IO, CPU-bound → Default, mellanliggande → nedärvning från scope. För Android rekommenderas att starta korutinen på den dispatcher där huvudarbetet utförs och före UI-uppdatering växla till Main via withContext.

  • Kör inte IO-operationer på Main-dispatchern — detta blockerar UI
  • Kör inte CPU-intensiva uppgifter på IO-dispatchern — detta förbrukar IO-poolens trådar ineffektivt
  • Använd limitedParallelism för att kontrollera parallellism vid massiva IO-operationer
  • Växla dispatcher med withContext, inte genom att skapa ny scope
  • Ärv dispatcher från scope, om korutinen inte kräver en specifik pool

För komplexa scenarier, kombinera dispatchers med operatorn +: Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler. Detta skapar en CoroutineContext med specificerad dispatcher, felhantering och en isolerad Job-hierarki.

Vanliga frågor

Vad är skillnaden mellan Dispatchers.IO och Dispatchers.Default?

Dispatchers.IO använder en pool på upp till 64 trådar för I/O-bound operationer (väntan på in-/utmatning), medan Dispatchers.Default använder en pool baserat på antalet CPU-kärnor för beräkningsuppgifter. Vid trådbrist kan båda poolerna dela trådar med varandra.

Kan jag skapa min egen dispatcher i Kotlin Coroutines?

Ja, använd newSingleThreadContext() för en entrådad eller newFixedThreadPoolContext() för en fast pool. För produktion, använd limitedParallelism() baserat på befintliga dispatchers — detta är effektivare än att skapa nya pooler.

Vad händer när Dispatchers.Main anropas i en bakgrundstråd?

Om Dispatchers.Main inte är tillgänglig (t.ex. i ett JUnit-test eller bakgrundstjänst), kastas IllegalStateException. För tester, använd TestCoroutineDispatcher, för bakgrundstjänster — Dispatchers.IO eller Default.

Hur begränsar jag antalet parallella IO-operationer?

Använd Dispatchers.IO.limitedParallelism(N), där N är det maximala antalet parallella trådar. Detta förhindrar att poolen töms vid massiva förfrågningar och ger kontrollerad parallellism.

När ska jag använda Dispatchers.Unconfined?

Dispatchers.Unconfined är lämplig för mellanliggande operationer: lätta datatransformationer innan data skickas till en annan dispatcher, testscenarier. I Android-produktionskod rekommenderas den inte på grund av osäker exekveringstråd efter avstängning.

Sammanfattning

  • Dispatchers — CoroutineContext-komponenter som bestämmer korutinernas exekveringstrådar
  • Dispatchers.Main — för Android UI-operationer, en huvudtråd
  • Dispatchers.IO — för nätverks- och diskoperationer, pool upp till 64 trådar
  • Dispatchers.Default — för CPU-intensiva beräkningar, pool baserat på kärnor
  • Dispatchers.Unconfined — utan trådbindning, för mellanliggande operationer
  • withContext — den huvudsakliga mekanismen för att växla mellan dispatchers inuti en korutin
  • Felaktigt val av dispatcher leder till UI-fördröjningar eller ineffektiv resursanvändning

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också