在背压问题---Rxjava 中,讲到,背压问题产生的原因以及Rxjava的相关处理办法,那在Kotlin时代,有木有更好的替代方案呢?
基于协程的Flow
Flow
是基于协程使用的,它不需要一些巧妙设计的解决方案来明确处理背压,在 Flow
中,不同于一些传统的响应式框架,它的背压管理是使用 Kotlin
挂起函数 suspend
实现的, 它里面所有的函数方法都是使用 suspend
修饰符标记,这个修饰符就是为了暂停调度者的执行不阻塞线程。因此, Flow<T>
在同一个协程中发射和收集时,如果收集器跟不上数据流,它可以简单地暂停元素的发射,直到它准备好接收更多。
Flow背压策略
主要有如下三种,可以对比 Rxjava Flowable
中的5种有异曲同工的作用。
SUSPEND
(buffer()
方法中默认):会将当前协程挂起,直到缓冲区中的数据被消费了DROP_OLDEST
:它会丢弃最老的数据DROP_LATEST
: 它会丢弃最新的数据
参考源码:
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND): Flow<T> {})
buffer()
方法中可定义 onBufferOverflow
参数,于是就有了:
1、SUSPEND
策略,默认方式,会挂起当前函数,直到执行完毕
对应的 buffer()
方法
2、DROP_OLDEST
策略
也就是:
在一些些情况下,由于生产消费速率不匹配的问题, conflate
将做取舍,丢弃掉旧数据,只有在收集器空闲之前发出的最后一个元素才被收集, 这样做的好处就是执行时间缩短,不受积压影响,但相应的是数据丢失。
3、DROP_LATEST
策略
按源码中的解释是,collectLatest
作用在于当原始流发出一个新的值的时候,前一个值的处理将被取消,也就是不会被接收, 和 conflate
的区别在于它不会用新的数据覆盖,而是每一个都会被处理,只不过如果前一个还没被处理完后一个就来了的话,处理前一个数据的逻辑就会被取消。
也就是:
策略方案对比
如果每一个事件都很重要, 可以用:buffer()
,即 SUSPEND
策略;
如果事件可以覆盖,只需获取最新的, 例如:数据库刷新,可以用:collectLates
t,即 DROP_LATEST
策略;(ps:我们在跑步项目中,使用的数据库记录数据,也有可能会频繁更新,可以考虑这样的策略)
如果事件事件不重要,只关心发送次数,可以用:conflate()
,即 DROP_OLDEST
策略
Flow
与 Rxjava
的简单比较
RxJava Flowable
和 Kotlin Flow
都支持背压,但仍然存在差异。
主要是 RxJava
基于内置的背压支持,它从下到上工作(下游能够在需要更多值时告诉上游),而 Kotlin Flow
背压主要基于 suspend
挂起函数
Rxjava
会将它进行阻塞,而 Flow
则将它挂起/暂停。
如果项目中有使用Rxjava 就可以不用flow,Rxjava 的代码量是相当多的; 如果项目中使用了协程,就可以不用Rxjava,协程相对来说更轻量级,适合新项目,初学者;