Какие знаешь компоненты в Coroutines?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Компоненты Kotlin Coroutines
Coroutines представляют собой набор компонентов, которые вместе образуют целостную систему асинхронного программирования. Вот основные компоненты, которые я разделю на несколько категорий.
Базовые строительные блоки
CoroutineScope
Контекст, в котором запускаются корутины. Управляет временем жизни корутин через Job. Основные реализации:
- GlobalScope - глобальная область видимости (используется с осторожностью)
- CoroutineScope() - создание пользовательской области
- Области жизненного цикла в Android:
viewModelScope,lifecycleScope
class MyViewModel : ViewModel() {
fun fetchData() {
viewModelScope.launch {
// Корутина, автоматически отменяемая при очистке ViewModel
val data = repository.loadData()
}
}
}
Job
Представляет отменяемую задачу с иерархической структурой. Управляет состоянием корутины:
- New, Active, Completing, Completed, Cancelling, Cancelled
- Можно отменять, ждать завершения, проверять состояние
val job = CoroutineScope(Dispatchers.IO).launch {
// Длительная операция
}
// Позже отменяем
job.cancel()
Deferred
Job с результатом (аналог Future/Promise). Возвращается async-корутиной:
val deferred: Deferred<Int> = async {
calculateSomething()
}
// Получаем результат (может быть приостановкой)
val result = deferred.await()
Контексты и диспетчеры
CoroutineContext
Набор элементов, определяющих поведение корутины:
- Диспетчер - определяет поток выполнения
- Job - управление жизненным циклом
- Обработчик исключений - обработка ошибок
- Имя - для отладки
val customContext = Dispatchers.IO + CoroutineName("MyCoroutine") + SupervisorJob()
CoroutineDispatcher
Определяет, на каком потоке/пуле потоков будет выполняться корутина:
- Dispatchers.Default - для CPU-интенсивных задач (размер пула = количеству ядер)
- Dispatchers.IO - для блокирующих IO-операций (динамический пул до 64 потоков)
- Dispatchers.Main - главный поток (UI поток в Android/Swing/JavaFX)
- Dispatchers.Unconfined - не привязан к конкретному потоку (стартует в текущем, продолжает в любом)
- Пользовательские диспетчеры через
newSingleThreadContext,newFixedThreadPoolContext
Строители корутин
launch
Запускает корутину без возвращаемого результата ("fire-and-forget"):
scope.launch {
// Асинхронный код
doWork()
// Нет возвращаемого значения
}
async
Запускает корутину, возвращающую Deferred<T>:
val result1: Deferred<Int> = async { fetchData1() }
val result2: Deferred<Int> = async { fetchData2() }
// Параллельное выполнение с ожиданием обоих результатов
val sum = result1.await() + result2.await()
runBlocking
Блокирует текущий поток до завершения корутины (используется в основном в тестах и main-функциях):
fun main() = runBlocking {
// Блокирует main-поток до завершения
launch {
delay(1000)
println("World")
}
println("Hello")
}
withContext
Смена контекста внутри корутины с возвратом результата:
suspend fun loadData(): Data = withContext(Dispatchers.IO) {
// Выполняется в IO-диспетчере
performNetworkRequest()
}
Обработка исключений
CoroutineExceptionHandler
Обработчик необработанных исключений:
val handler = CoroutineExceptionHandler { _, exception ->
println("Поймано исключение: $exception")
}
scope.launch(handler) {
throw RuntimeException("Ошибка в корутине")
}
SupervisorJob и SupervisorScope
Режим, при котором сбой одной дочерней корутины не отменяет другие:
// SupervisorJob не распространяет отмену на родителя
val supervisor = SupervisorJob()
// Или используем supervisorScope
supervisorScope {
launch {
// Если эта корутина упадет, другие продолжат работу
throw RuntimeException()
}
launch {
// Эта корутина продолжит работу
delay(1000)
}
}
Потоковые API
Flow
Асинхронный поток данных (cold stream), аналогичный RxJava Observable:
fun getNumbers(): Flow<Int> = flow {
for (i in 1..10) {
delay(100)
emit(i) // Выдача значения
}
}
// Сбор
scope.launch {
getNumbers()
.filter { it % 2 == 0 }
.map { it * 2 }
.collect { value ->
println(value)
}
}
Channel
Горячий поток для коммуникации между корутинами (аналог BlockingQueue):
val channel = Channel<Int>()
// Producer
launch {
for (x in 1..5) {
channel.send(x * x)
}
channel.close()
}
// Consumer
launch {
for (y in channel) {
println(y)
}
}
Специальные конструкции
select
Ожидание нескольких приостанавливаемых функций с выбором первой завершившейся:
suspend fun selectExample() {
val channel1 = Channel<Int>()
val channel2 = Channel<Int>()
select<String> {
channel1.onReceive { value ->
"from channel1: $value"
}
channel2.onReceive { value ->
"from channel2: $value"
}
}
}
Mutex и Semaphore
Средства синхронизации для корутин:
val mutex = Mutex()
suspend fun safeUpdate() {
mutex.withLock {
// Критическая секция
sharedResource.update()
}
}
Интеграционные компоненты
Для интеграции с существующими API существуют:
- suspendCancellableCoroutine - адаптация callback-API к suspend-функциям
- callbackFlow - создание Flow из callback-API
- CompletableDeferred - ручное создание Deferred
suspend fun awaitCallback(): Result = suspendCancellableCoroutine { continuation ->
val callback = object : SomeCallback {
override fun onSuccess(result: Result) {
continuation.resume(result)
}
override fun onError(error: Throwable) {
continuation.resumeWithException(error)
}
}
api.registerCallback(callback)
// Обработка отмены
continuation.invokeOnCancellation {
api.unregisterCallback(callback)
}
}
Эти компоненты вместе образуют мощную, но гибкую систему, которая позволяет писать асинхронный код в последовательном стиле, управлять ресурсами, обрабатывать ошибки и эффективно использовать потоки выполнения.