Kotlin Flow 操作符 buffer、conflate 和 collectLatest 的区别
Kotlin Flow 操作符 buffer、conflate 和 collectLatest 的区别
- Flow 操作符 buffer、conflate 和 collectLatest 都是 Flow 的扩展函数,是主要用于处理 Backpressure 背压问题(即下游收集器无法及时处理上游发射的数据流的情况)的操作符,解决生产者生成数据速度超过消费者处理数据速度所引发的问题
- buffer 通过在生产者和消费者之间引入一个缓冲区,可以指定缓冲区容量和溢出策略,允许生产者和消费者以不同的速度独立工作(生产者可以继续快速生成数据,而不需要等待消费者处理完每一条数据,会将未处理的数据暂存到缓冲区中,消费者则可以按照自己的速度节奏处理这些数据,而不会因为消费者处理速度慢而阻塞),可以在一定程度上有效缓解生产者和消费者之间的速率不匹配问题,从而减轻背压题
- conflate 会在消费者处理数据期间,忽略(丢弃,conflate 翻译合并,相当于它会“合并” 掉中间的数据一样)生产者持续产生的中间数据,只处理最新的数据,意味着消费者在处理完当前数据后,直接处理最新产生的数据,中间旧的数据会被跳过,这样可以避免大量的数据堆积,从而减轻消费者的负担,可以达到节省内存提高效率的目的,能够显著缓解背压问题
- collectLatest 用于在收集数据流时自动取消之前在进行的收集操作,当新的数据项被发射时,在接收到新的数据项时,会立即取消当前正在执行的收集操作,并开始一个新的收集操作来处理最新的数据项,可以确保只处理最新的数据,而取消旧数据的处理操作(确保了只有最新的数据被处理完成),也能够避免了在处理中间过时数据过程中可能会导致的潜在问题,也能以自身的特性来缓解背压问题
buffer
- 当生产者生成数据时,数据会被暂存在缓冲区中,消费者会从缓冲区中取出数据进行处理,当缓冲区满了的话,生产者会暂停生成数据,直到消费者从缓冲区中继续取出数据腾出可用空间,另外缓冲区大小需要根据实际需求合理配置,如果缓冲区过小,可能会导致生产者频繁暂停,如果缓冲区过大,可能会占用过多内存
- capacity 指定缓冲区的容量,当缓冲区达到指定的容量时,生产者会被阻塞(默认 BUFFERED),默认情况下,buffer 的容量为 64 默认的缓冲区大小
- onBufferOverflow 指定缓冲区溢出策略
- BufferOverflow.SUSPEND 默认策略,当缓冲区满时,生产者会挂起,直到缓冲区有空间 暂停发射端,直到缓冲区有空闲空间
- BufferOverflow.DROP_OLDEST 当缓冲区满时,删除缓冲区中最旧的数据,为新数据腾出空间
- BufferOverflow.DROP_LATEST 当缓冲区满时,丢弃最新的数据
- buffer 属于中间操作符
conflate
- 在处理高频产生的数据时,能够跳过中间值只处理最新的数据,不过不会取消当前正在处理的操作,避免处理中间过时的数据,这在处理快速连续更新的数据流时非常有用,比如传感器数据实时更新数据可能引起的频繁的 UI 更新(只关心最新的状态,而不需要处理中间过时的状态)
- conflate 操作符等同于 buffer 操作符在 capacity = 0,onBufferOverflow = BufferOverflow.DROP_OLDEST 条件下的情况
- conflate 属于中间操作符
collectLatest
- 在处理高频产生的数据时,当接收到新的数据时,会立即取消当前正在执行的收集操作(如果存在的话,意味着会打断消费者的消费过程),然后开始处理最新的数据项,比如在搜索框中接收用户输入且实时更新搜索结果的情况(侧重于只需要最新的搜索处理逻辑操作,立即取消之前的搜索操作)
- collectLatest 属于末端操作符
总结
- buffer 能够将未处理的数据暂存到缓冲区中,消费者可以按照自己的节奏速度消费数据,支持设置缓冲区大小和溢出策略
- conflate 跳过中间值,只保留最新的值(缓存池相当于直接满了,用新数据覆盖老数据),但不会取消当前的处理操作
- collectLatest 取消当前正在进行的处理操作,直接跳到最新的值(每一个数据都会被(开始)处理,只不过还没处理完后一个数据就来了,处理逻辑操作被打断了)