Перейти к основному содержимому

Корутины в Kotlin

Разработчику Архитектору

Корутины в Kotlin

Корутины (kotlinx.coroutines) — способ писать асинхронный код без callback-ада. Один поток JVM может обслуживать тысячи suspend-операций.

Нужны для Ktor, Android (сеть, Room), Compose.


suspend и launch

import kotlinx.coroutines.*

suspend fun fetchTitle(): String {
delay(100) // не блокирует поток ОС
return "Kotlin"
}

fun main() = runBlocking {
launch {
println("A: ${fetchTitle()}")
}
launch {
println("B: ${fetchTitle()}")
}
}

runBlocking — только в main и тестах; в Android — lifecycleScope, в Ktor — уже внутри сервера.


async — параллельные результаты

suspend fun loadDashboard(): Pair<String, Int> = coroutineScope {
val title = async { fetchTitle() }
val count = async { fetchCount() }
title.await() to count.await()
}

Scope и structured concurrency

ScopeГде
runBlockingтесты, CLI
coroutineScopeдочерние корутины завершатся вместе
supervisorScopeошибка в одном child не отменяет остальных
viewModelScopeAndroid ViewModel
class Repo {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

fun refresh(onDone: (String) -> Unit) {
scope.launch {
val data = fetchTitle()
withContext(Dispatchers.Main) {
onDone(data)
}
}
}

fun close() {
scope.cancel()
}
}

Flow — поток значений

fun ticker(): Flow<Int> = flow {
var i = 0
while (true) {
emit(i++)
delay(500)
}
}

// collect в корутине:
// ticker().take(5).collect { println(it) }

StateFlow / SharedFlow — hot-потоки для UI (Compose, ViewModel).


Обработка ошибок

scope.launch {
try {
risky()
} catch (e: IOException) {
// лог, retry
}
}

CoroutineExceptionHandler — для необработанных исключений в launch.


Тесты

import kotlinx.coroutines.test.runTest

@Test
fun loadsTitle() = runTest {
val title = fetchTitle()
assertEquals("Kotlin", title)
}

Зависимость: kotlinx-coroutines-test.


Сравнение с Java

JavaKotlin
CompletableFutureasync / suspend
ExecutorServiceDispatchers.IO
Virtual threads (21+)корутины легче в DSL

Связанные материалы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).