一、认识Channel(热流)
协程中的通道(Channel)是一种用于在协程之间传输数据的机制。通道可以被看作是生产者-消费者模式的实现,其中一个协程可以发送数据到通道,而另一个协程则可以从通道接收数据。通道具有缓冲区,允许在发送者和接收者之间进行异步通信。
与Flow冷流的区别:Channel热流的特点是,数据流在创建后立即开始,不受订阅者的影响,而Flow
是一种冷流,这意味着它的数据流在没有订阅者时是不会启动的
Chnannel的协程通信实例:
@Test
fun testchannel() = runBlocking {
val channel = Channel<Int>()
//生产者
val producer = GlobalScope.launch {
var i = 0
while (true){
delay(1000)
channel.send(++i)
println("send $i")
}
}
//消费者
val consumer = GlobalScope.launch {
while (true) {
val element = channel.receive()
println("receive $element")
}
}
joinAll(producer, consumer)
}
结果如下,
二、Channel的容量
默认情况下,Channel的容量是0,就是发出一个才能接收一个
三、Channel迭代
1.使用 for (element in channel)
的形式可以从通道中依次获取元素,直到通道被关闭或者没有更多元素可用为止。
2.使用iterator迭代器
实例代码如下:
fun testchannel() = runBlocking {
val channel = Channel<Int>(Channel.UNLIMITED)
//生产者
val producer = GlobalScope.launch {
for (i in 1..5){
channel.send(i * i)
println("send ${i * i}")
}
}
//消费者
val consumer = GlobalScope.launch {
val iterator = channel.iterator()
while (iterator.hasNext()){
val element = iterator.next()
println("receive $element")
delay(2000)
}
}
joinAll(producer, consumer)
}
@Test
fun testchannel() = runBlocking {
val channel = Channel<Int>(Channel.UNLIMITED)
//生产者
val producer = GlobalScope.launch {
for (i in 1..5){
channel.send(i * i)
println("send ${i * i}")
}
}
//消费者
val consumer = GlobalScope.launch {
val iterator = channel.iterator()
for (element in channel){
println("receive $element")
delay(2000)
}
}
joinAll(producer, consumer)
}
四、produce与actor
@Test
fun testchannel1() = runBlocking {
//生产者便捷方式
val receiveChannel: ReceiveChannel<Int> = GlobalScope.produce {
repeat(100){
delay(1000)
send(it)
}
}
//消费者
val consumer = GlobalScope.launch {
for (i in receiveChannel){
println("receive: $i")
}
}
consumer.join()
}
五、Channel的关闭 ![](https://img-blog.csdnimg.cn/direct/713439a4a2f8468e8f548d91b4d6bb80.png)
就字面意思,上面讲的很清楚了,我用一个事例代码解释一下
@Test
fun testchannel3() = runBlocking {
val channel = Channel<Int>(3)//设置通道为3
//生产者
val producer = GlobalScope.launch {
List(3) {
channel.send(it)
println("send $it")
}
channel.close()
println("Befor CloseForSend: ${channel.isClosedForSend}" + " "+
"CloseForReceive: ${channel.isClosedForReceive}")
}
//消费者
val consumer = GlobalScope.launch {
val iterator = channel.iterator()
for (element in channel){
println("receive $element")
delay(1000)
}
println("After CloseForSend: ${channel.isClosedForSend}" +" "+
"CloseForReceive: ${channel.isClosedForReceive}")
}
joinAll(producer, consumer)
}
结果:
可见,在关闭的时候,只接收到0,而1,2没有接收到,所以CloseForSend: true CloseForReceive: false,等到1, 2也被接收的时候 CloseForReceive也为true了
六、BroadcastChannel(广播通道一对多)
通过调用 openSubscription
函数可以创建一个用于接收消息的 ReceiveChannel(相当订阅)
就是通过订阅的方式来实现一对多的传播。
@Test
fun testchannel4() = runBlocking {
val broadcastChannel = BroadcastChannel<Int>(Channel.BUFFERED)//设置通道为3
//生产者
val producer = GlobalScope.launch {
List(3) {
delay(1000)
broadcastChannel.send(it)
}
broadcastChannel.close()//发送完成后关闭
}
//广播接收
List(3){index ->
GlobalScope.launch {
val receiveChannel = broadcastChannel.openSubscription()
for (i in receiveChannel){
println("$i")
}
}
}.joinAll()
}