Kotlin协程Channel使用

一、Channel
1、定义

Flow是冷流,本质上可以说是一个单线程操作,只有开始收集时,上流代码才会启动;而Channel是一个并发安全的队列,可以用来连接不同的协程,实现不同协程之间的通信。
在这里插入图片描述
 

2、基本使用
runBlocking {
    val channel = Channel<Int>()
    GlobalScope.launch(Dispatchers.IO) {
        channel.send(10)
        delay(1000)
        channel.send(100)
        delay(1000)
        channel.send(1000)
    }

    GlobalScope.launch(Dispatchers.Main) {
        val iterator = channel.iterator()
        while(iterator.hasNext()) {
            val element = iterator.next()
            Log.i("MainActivity", "接收到元素:$element")
        }
    }
}
// I: 接收到元素:10
// I: 接收到元素:100
// I: 接收到元素:1000

 

3、Channel容量

Channel的容量或者说缓冲区大小,默认为0,当消费者消费慢了,那么生产者会等待,反之生产者生产慢了,消费者会等待。如果想要指定缓冲区大小,可以在构建时传入。

runBlocking {
    val channel = Channel<Int>()
    GlobalScope.launch(Dispatchers.IO) {
        var i = 0
        while (true) {
            i++ // 为了方便输出日志,我们将自增放到前面
            Log.i("MainActivity", "before send $i")
            channel.send(i)
            Log.i("MainActivity", "after send $i")
            delay(1000)
        }
    }

    GlobalScope.launch(Dispatchers.Main) {
        while (true) {
            delay(5000) // receive 之前延迟 5s
            val element = channel.receive()
            Log.i("MainActivity", "接收到元素:$element")
        }
    }
}
// I: before send 1
5秒后
// I: 接收到元素:1
// I: after send 1
1秒后
// I: before send 2
5秒后
// I: 接收到元素:2
// I: after send 2

我们故意让收端的节奏放慢,你就会发现,send 总是会挂起,直到 receive 之后才会继续往下执行。
 
(1)修改Channel缓存模式为UNLIMITED

val channel = Channel<Int>(Channel.UNLIMITED)
// I: before send 1
// I: after send 1
// I: before send 2
// I: after send 2
// I: before send 3
// I: after send 3
// I: before send 4
// I: after send 4
// I: before send 5
// I: after send 5
// I: 接收到元素:1

UNLIMITED表示不限制,发送端和接收端各不等待对方,正常按自己节奏发送和接收。
 
(2)修改Channel缓存模式为CONFLATED

val channel = Channel<Int>(Channel.CONFLATED)
// I: before send 1
// I: after send 1
// I: before send 2
// I: after send 2
// I: before send 3
// I: after send 3
// I: before send 4
// I: after send 4
// I: before send 5
// I: after send 5
// I: 接收到元素:5

CONFLATED表示合并,每次有新元素过来,都会用新的替换旧的,也就是说我发了个1、2、3、4、5 之后收端才接收的话,就只能收到 5 了。
 
(3)修改Channel缓存为某个数量

val channel = Channel<Int>(2)
// I: before send 1
// I: after send 1
1秒后
// I: before send 2
// I: after send 2
1秒后
// I: before send 3
3秒后
// I: 接收到元素:1
// I: after send 3
1秒后
// I: after send 4

 

4、Channel关闭

说起关闭,我们就容易想到 IO,如果不关闭可能造成资源泄露,那么 Channel 的关闭是个什么概念呢?Channel 其实内部的资源就是个缓冲区,这个东西本质上就是个线性表,就是一块儿内存,所以如果我们开了一个 Channel 而不去关闭它,其实也不会造成什么资源泄露,发端如果自己已经发完,它就可以不理会这个 Channel 了。嗯,看上去好像没什么问题是吧?
但是,这时候在接收端就比较尴尬了,它不知道会不会有数据发过来,然后它就一直这样等待,这就变成了资源的不释放了。
那么 Channel 的关闭究竟应该有谁来处理呢?正常的通信,如果是单向的,比较推荐由发端处理关闭。而对于双向通信的情况,就要考虑协商了,双向通信从技术上两端是对等的,但业务场景下通常来说不是,建议由主导的一方处理关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值