Flow中的buffer详解

什么是buffer

  • 上游(emit)下游(collect) 之间插入一个有界/无界缓冲队列(底层是 Channel),把两端解耦:上游可以先"塞进队列就走",下游慢慢消费。
  • 主要用于背压处理并发解耦
scss 复制代码
[ emitter ] --(buffer queue)--> [ collector ]

基本用法与参数

ini 复制代码
flow.buffer(
    capacity: Int = Channel.BUFFERED,          // 常用:Channel.BUFFERED(≈64) / UNLIMITED / RENDEZVOUS(0)
    onBufferOverflow: BufferOverflow = SUSPEND // 也可:DROP_OLDEST / DROP_LATEST
)
  • SUSPEND(默认) :队列满了就挂起上游,保证不丢数据。

  • DROP_OLDEST:丢最老的,保最新的一批("滑窗")。

  • DROP_LATEST:丢最新的(更少见)。

  • capacity = 0(RENDEZVOUS):相当于无缓冲,交接点对点同步,不解耦。

  • UNLIMITED:不建议轻易用,可能吃内存。

和其它操作符的区别

  • conflate() ≈ buffer(1, DROP_OLDEST):永远只保"最新值",中间值丢弃,适合"只关心最新状态"的 UI。

  • collectLatest / mapLatest :来了新值会取消前一个下游处理(不是丢缓存,而是取消处理过程),适合"处理很重但只要最新"的场景(比如渲染)。

  • buffer 不会取消处理,只影响排队与丢弃策略

典型场景

  • 上游快、下游慢:日志、传感器、网络流 → buffer(64, SUSPEND)。

  • 只关心最新:搜索框联想、进度流 → conflate() 或 buffer(1, DROP_OLDEST)。

  • 限制突发 + 保持近实时:buffer(n, DROP_OLDEST)(比如 n=8/16)。

与flowOn的关系

  • flowOn(Dispatchers.IO) 自带一个缓冲边界(类似 buffer(Channel.BUFFERED)),使上下文切换处天然解耦。
  • 需要更深队列时,可在 flowOn 之后再加一个 buffer(k) 增大吞吐。
scss 复制代码
upstream
  .map { ioHeavy() }
  .flowOn(Dispatchers.IO) // 这里已形成一个缓冲边界
  .buffer(32)             // 再加一段队列
  .collect { ui() }

放置位置(很关键)

把 buffer() 放在慢操作之前,切开阻塞链条:

scss 复制代码
flow
  .map { fast() }
  .buffer(64)     // 切断:避免后面的慢步骤"顶住"前面
  .map { slow() }
  .collect { consume() }

与 SharedFlow/StateFlow

  • 它们自身有 replay/extraBufferCapacity/onBufferOverflow 。若再套 buffer(),会再多一层队列,只有在确实需要二级缓冲/隔离时才加。

小示例:对比分离前后

scss 复制代码
val f = flow {
  repeat(100) { i ->
    emit(i)             // 生产很快
    delay(10)
  }
}

// 无 buffer:下游慢会直接"顶住"上游
f.collect { delay(50); println(it) }

// 有 buffer:先排队,上游更流畅(满了再按策略处理)
f.buffer(32, onBufferOverflow = BufferOverflow.SUSPEND)
 .collect { delay(50); println(it) }

选择容量的小经验

  • 先用默认(≈64),观察队列积压内存(可埋点 length/max)。

  • 若突发明显且不想丢数据:升大一点,如 128/256。

  • 只要最新:conflate() 或 buffer(1, DROP_OLDEST)。

一句话总结

buffer 用"队列"把快上游与慢下游隔离;SUSPEND 保正确性,DROP_OLDEST 保实时性;把 buffer 放在慢步骤之前最有效。

相关推荐
GISer_Jing4 小时前
明天好好总结汇总分析博客
前端·javascript·面试
sophie旭15 小时前
一道面试题,开始性能优化之旅(8)-- 构建工具和性能
前端·面试·性能优化
Focusbe18 小时前
百变AI助手:离线优先数据同步方案设计
前端·后端·面试
nice_lcj52020 小时前
深入理解ArrayList与LinkedList:Java集合框架核心对比(含实战案例+面试考点)
java·面试
nju_spy20 小时前
大模型面经(一) Prompt + RAG + 微调
人工智能·面试·lora·大模型·rag·提示词工程·peft微调
聪明的笨猪猪20 小时前
Java 内存模型(JMM)面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
9号达人1 天前
Java20 新特性详解与实践
java·后端·面试
熊小猿1 天前
ArrayList 与 LinkedList 的区别
java·面试
sophie旭1 天前
一道面试题,开始性能优化之旅(5)-- 浏览器和性能
前端·面试·性能优化
AAA修煤气灶刘哥2 天前
面试必问的CAS和ConcurrentHashMap,你搞懂了吗?
后端·面试