持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情
Channel的关闭
和消息队列不同,一个Channel可以通过被关闭来表明没有更多的元素将会进入通道。
然后接收者可以定期的使用for循环来从Channel中接收元素。
一个close()操作,就是向Channel发送了一个特殊的关闭指令。这个当这个关闭操作被
Channel收到的时候,通道就进入了迭代停止状态。也就是说之后通道将不会有数据更新了。它能够保证所有先前发送出去的元素都在Channel收到close消息前被接收到
fun main() = runBlocking {
val channel = Channel<Int>()
launch {
for (x in 1..5) channel.send(x * x)
channel.close() // 我们结束发送
}
// 这里我们使用 `for` 循环来打印所有被接收到的元素(直到通道被关闭)
for (y in channel) println(y)
println("结束!")
}
- produce和actor返回的Channel都会随着对应的协程执行完毕而关闭。正式因为这样Channel才被称为热数据流。
- 对于一个Channel,如果我们调用流它的close方法。它会立即停止接收新元素,也就是说这时它的isClosedForSend立即返回true。而由于Channel缓冲区的存在,这个时候可能还有一些元素没有被处理完,因此要等所有元素都被读取之后isClosedForReceive才会返回true。
- Channel的生命周期最好由主导方来维护,建议由主导的一方实现关闭。
BroadcastChannel
发送端和接收端在Channel中存在一对多的情形,从数据处理本身来讲,虽然有多个接收端,但是同一个元素只会一个接收端读到。广播则不然,多个接收端不存在互斥行为。
多路复用
数据通信系统或计算机网络系统中,传输媒体的带宽或容量往往会大于传输单一信号的需求,为了有效的需求,为了有效地利用通信线路,希望一个信道同时传输多路信号,这就是所谓的多路复用技术。
复用多个await
两个api分别从网络和本地缓存获取数据,期望哪个先返回就用哪个做展示。
复用多个Channel
和await类似,会接收到最快的那个channel消息
fun `test channel select`() = runBlocking {
val channels = listOf(Channel<Int>(), Channel<Int>())
GlobalScope.launch {
delay(50)
channels[0].send(0)
}
GlobalScope.launch {
delay(100)
channels[1].send(1)
}
val select = select<Int> {
channels.forEach {
it.onReceive { value ->
value
}
}
}
println(select)
delay(1000)
}
SelectCause
并不是所有的事件可以使用select的,只有SelectCauseN类型的事件
1.SelectCause0:对应事件没有返回值,例如join,那么onJoin就是SelectCauseN,使用时,onJoin的参数是一个无参函数
2.SelectCause1:对应事件有返回值,例如onAwait,onReceive
3.SelectCause3:对应事件有返回值,此外还要一个额外参数,例如Channel.onSend,一个参数为Channel数据类型的值,一个为发送成功时的回调
fun `test channel send select`() = runBlocking {
val channels = listOf(Channel<Int>(), Channel<Int>())
launch {
select<Unit?> {
launch {
delay(100)
channels[0].onSend(0) {
println("onSend 0")
}
}
launch {
delay(50)
channels[1].onSend(1) {
println("onSend 1")
}
}
}
}
GlobalScope.launch {
println(channels[0].receive())
}
GlobalScope.launch {
println(channels[1].receive())
}
}
使用Flow实现多路复用
fun `test flow merge`() = runBlocking {
listOf(::getInfoForLocal1, ::getInfoForLocal2)
.map { function ->
function.call()
}.map { deferred ->
flow { emit(deferred.await()) }
}.merge()
.collect {
println(it)
}
}