0Pricing
Kotlin Academy · Урок

Основы каналов: send, receive и close

Создавайте каналы, отправляйте и получайте значения и правильно закрывайте их.

«Основы каналов: send, receive и close» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Что такое канал?

Channel — примитив сопрограмм для обмена данными между сопрограммами: подобие блокирующей очереди, но с приостановкой вместо блокировки. Представьте его как трубу: одна сторона отправляет данные, другая принимает.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val channel = Channel<Int>()
    launch {
        for (i in 1..5) channel.send(i)
        channel.close()
    }
    for (x in channel) println(x) // 1 2 3 4 5
}

send и receive

send(value) приостанавливается, пока получатель не будет готов. receive() приостанавливается, пока не станет доступно значение.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<String>()
    launch {
        ch.send("ping")
        println("sent")
    }
    val msg = ch.receive()
    println("received: $msg")
}

Закрытие канала

channel.close() сообщает, что больше значения отправляться не будут. Получатели получают оставшиеся буферизованные значения, после чего цикл for завершается.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>(3)
    launch {
        repeat(3) { ch.send(it) }
        ch.close()  // signal done
    }
    for (v in ch) println(v) // 0 1 2, then loop ends
    println("Channel consumed")
}

isClosedForSend / isClosedForReceive

Проверяйте состояние канала с помощью isClosedForSend — отправка больше не разрешена — и isClosedForReceive — все значения получены.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>()
    launch {
        ch.send(1)
        ch.close()
    }
    println(ch.receive())
    println("isClosedForReceive: ${ch.isClosedForReceive}")
}

Построитель производителя

produce { } — это конструктор сопрограмм, который создаёт сопрограмму-производитель и возвращает ReceiveChannel. Канал автоматически закрывается после завершения блока.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.squares(n: Int) = produce<Int> {
    for (i in 1..n) send(i * i)
}
fun main() = runBlocking {
    val sq = squares(5)
    for (v in sq) println(v) // 1 4 9 16 25
}

Расширение consumeEach

consumeEach { } перебирает канал и отменяет его, если блок выбрасывает исключение, предотвращая утечки.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = produce<String> {
        send("a"); send("b"); send("c")
    }
    ch.consumeEach { println(it) }
}

tryReceive и trySend

Неприостанавливающие альтернативы: trySend и tryReceive немедленно возвращают ChannelResult, не приостанавливая выполнение.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val ch = Channel<Int>(1)
    val sendResult = ch.trySend(42)
    println("Sent: ${sendResult.isSuccess}")
    val recvResult = ch.tryReceive()
    println("Got: ${recvResult.getOrNull()}")
}

Разветвление: несколько получателей

Несколько сопрограмм могут получать данные из одного канала, распределяя работу. Это шаблон разветвления.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val tasks = produce { repeat(6) { send(it) } }
    repeat(3) { worker ->
        launch {
            for (task in tasks) {
                println("Worker $worker: task $task")
            }
        }
    }
}

Сведение: несколько производителей

Несколько сопрограмм могут отправлять данные в один канал, объединяя результаты. Это шаблон сведения.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val results = Channel<String>()
    repeat(3) { i ->
        launch { results.send("result-$i") }
    }
    launch {
        repeat(3) { println(results.receive()) }
        results.close()
    }
}

Шаблон конвейера

Объединяйте каналы в конвейер, где каждый этап читает данные из одного канала и записывает их в другой. Это отлично подходит для рабочих процессов обработки данных.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.numbers() = produce { for (i in 1..5) send(i) }
fun CoroutineScope.doubled(input: ReceiveChannel<Int>) = produce { for (v in input) send(v * 2) }
fun main() = runBlocking {
    val nums = numbers()
    val doubled = doubled(nums)
    for (v in doubled) println(v) // 2 4 6 8 10
    coroutineContext.cancelChildren()
}

Канал и поток

Каналы горячие и содержат состояние: они существуют независимо от получения данных. Потоки холодные и декларативные: они запускаются заново при каждом сборе. Предпочитайте потоки для потоков данных, а каналы используйте для обмена между производителем и потребителем.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
// Flow (cold): each collect() re-runs the block
// Channel (hot): shared; multiple receivers share the same stream
fun main() = runBlocking { println("Flow = cold; Channel = hot") }

Быстрая проверка

Что происходит при вызове channel.close()?

Итоги

send и receive приостанавливаются, пока другая сторона не будет готова. Закрытие сообщает о завершении. Используйте производитель для автоматически закрывающихся производителей, consumeEach для безопасного перебора и каналы для шаблонов разветвления и сведения.

Часто задаваемые вопросы

Урок «Основы каналов: send, receive и close» бесплатный?

Да — полный текст урока «Основы каналов: send, receive и close» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «Основы каналов: send, receive и close»?

Создавайте каналы, отправляйте и получайте значения и правильно закрывайте их. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Основы каналов: send, receive и close»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы каналов: send, receive и close
  2. Типы каналов: Rendezvous, Buffered, Conflated, Unlimited
  3. Mutex и Semaphore для общего состояния
  4. Акторы и структурированное управление состоянием
← Назад к Kotlin Academy