前言
Kotlin协程引入了Channel和Flow,处理数据流,实现生成者-消费者模式,构建响应式应用。处理数据流和异步操作。
- Channel是一种热流
- Flow是一种冷流
Channel异步数据通信
Channel是用于协程之间通信的数据结构。内部基于协程调度器和锁。用队列存储发送数据,锁实现线程安全的数据访问。如果队列已满,发送协程将被挂起,直到有空间可用。接收协程会从队列中取出数据,如果队列为空,接收协程会被挂起,直到有数据可用。
有界Channel限制发送到Channel的数据量,无界Channel不做限制。
- capacity:Channel的容量,调用send发送数据,当receive消费慢的时候,会占用这个容量,当这个容量满后会触发丢弃策略(onBufferOverflow)。
- onBufferOverflow:当capacity溢出后触发
- onUndeliveredElement:当onBufferOverFlow为DROP_OLDEST或DROP_LATEST时,丢弃数据,关闭后继续发送消息,也会回调该对象
onBufferOverflow的取值:
- SUSPEND:将send方法挂起,直到capacity容量可以用为止(生产者剩余量小于capacity)
- DROP_OLDEST:丢弃最旧的数据
- DROP_LATEST:丢弃最新的数据
fun main(): Unit = runBlocking {
println("runBlocking")
val channel = Channel<Int>()
launch {
for (i in 1..5) {
delay(1000)
println(
"send i:$i threadName:${Thread.currentThread().name} " +
"threadId:${Thread.currentThread().id}"
)
channel.send(i)
}
// 这里注意在需要的时候关闭,不然一直处于未释放(当前线程一直在等待新消息的发送)
channel.close()
}
launch {
for (value in channel) {
println(
"value:$value threadName:${Thread.currentThread().name} " +
"threadId:${Thread.currentThread().id}"
)
}
}
}
输出结果:
send i:1 threadName:Test worker @coroutine#2 threadId:1
value:1 threadName:Test worker @coroutine#3 threadId:1
send i:2 threadName:Test worker @coroutine#2 threadId:1
value:2 threadName:Test worker @coroutine#3 threadId:1
send i:3 threadName:Test worker @coroutine#2 threadId:1
value:3 threadName:Test worker @coroutine#3 threadId:1
send i:4 threadName:Test worker @coroutine#2 threadId:1
value:4 threadName:Test worker @coroutine#3 threadId:1
send i:5 threadName:Test worker @coroutine#2 threadId:1
value:5 threadName:Test worker @coroutine#3 threadId:1
Channel,一个协程发送数据,一个协程接收数据,有助于协程之间异步通信。可以看出同threadId=1,但是不同的threadName。在同一个线程中实现了两个协程之间的发/收数据。
fun main() {
runBlocking(Dispatchers.Default) {
// 每次send只能有一个对应receive方法能接收到这个数据
val myChannel = Channel<Int>()
launch {
repeat(3) {
delay(100)
myChannel.send(it)
println("send $it")
}
myChannel.close()
println("send finish")
}
launch {
for (e in myChannel) {
delay(200)
println("receive1:$e")
}
println("Receive1 finish")
}
launch {
for (e in myChannel) {
delay(200)
println("receive2:$e")
}
println("Receive2 finish")
}
}
}
输出:
send 0
send 1
receive1:0
send 2
send finish
receive2:1
Receive2 finish
receive1:2
Receive1 finish
协程1和2交替获取数据。一个接收者收到数据,那另一个就不会收到相同的数据。
fun main() {
runBlocking(Dispatchers.Default) {
// capacity容量,没有receive方法接收数据的时候会占用这个容量
// onBufferOverflow 当capacity占满后,会触发丢弃策略。DROP_OLDEST(丢弃最久的数据)
val myChannel = Channel<Int>(capacity = 2, onBufferOverflow = BufferOverflow.DROP_OLDEST) {
println("Send Drop: $it")
}
launch {
repeat(4) {
delay(50)
myChannel.send(it)
println("Send: $it")
}
myChannel.close()
println("Send Finish")
}
launch {
for (e in myChannel) {
delay(300)
println("Receive1: $e")
}
println("Receive1 Finish")
}
}
}
发送比接收速度快,Channel容量为2, 触发BufferOverFlow逻辑,超过容量后丢弃最旧的一条数据(DROP_OLDEST)