Выбор канала в Kotlin
Иногда нужно ждать данные сразу из нескольких
очередей и реагировать на ту, где значение уже
лежит. Конструкция select из
kotlinx.coroutines.selects регистрирует
ветки onReceive и выполняет одну из них,
когда прием возможен без лишнего ожидания.
Если обе очереди уже содержат элементы, выбирается одна из веток по правилам библиотеки. Для наглядности обе заполняют заранее в буфер:
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.onReceive
import kotlinx.coroutines.selects.select
fun main() {
runBlocking {
val hot = Channel<String>(1)
val cold = Channel<String>(1)
hot.send("H")
cold.send("C")
val picked = select {
hot.onReceive { it }
cold.onReceive { it }
}
println(picked)
}
}
В консоли окажется одна буква - "H" или
"C". Функция select не читает оба канала
сразу: срабатывает ровно одна ветка, остальные
ждут следующего вызова.
Второй вызов select может забрать
оставшееся значение из соседней очереди, если
первая ветка уже опустошила свой канал:
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.onReceive
import kotlinx.coroutines.selects.select
fun main() {
runBlocking {
val east = Channel<Int>(1)
val west = Channel<Int>(1)
east.send(10)
west.send(20)
val first = select {
east.onReceive { it }
west.onReceive { it }
}
val second = select {
east.onReceive { it }
west.onReceive { it }
}
println(first + second)
}
}
Сумма 30 показывает, что оба числа
дошли до программы, хотя порядок веток в каждом
select мог отличаться. Так объединяют
несколько источников без жесткой привязки к
одному каналу.
Два канала символов с буфером на один элемент
содержат "p" и "q". Один
select с двумя onReceive
напечатайте выбранный символ.
Очереди строк "one" и "two"
лежат в каналах с одним слотом. Два подряд
select соберите обе строки в одну
переменную через пробел и выведите ее.