Основы каналов: 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 — локальная установка не требуется.
Все уроки этого курса
- Основы каналов: send, receive и close
- Типы каналов: Rendezvous, Buffered, Conflated, Unlimited
- Mutex и Semaphore для общего состояния
- Акторы и структурированное управление состоянием