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 放在慢步骤之前最有效。

相关推荐
weedsfly4 分钟前
观察者模式 vs 发布-订阅模式:从概念到实战,一次讲清楚
前端·javascript·面试
暗不需求5 分钟前
手写 AJAX:从 XMLHttpRequest 到封装一个简易 axios
前端·面试
嘟嘟071719 分钟前
从零理解远程 MCP:串联三个 MCP Server 打造 AI 自动化工作流
面试
不负岁月无痕22 分钟前
STL -- C++ 红黑树封装 Map 和 Set
java·c语言·开发语言·c++·面试
怕浪猫11 小时前
现在的"AI 原生应用"热潮,恰恰证明了大多数产品需求本身就是个草台班子
面试
TPBoreas14 小时前
MySQL性能优化面试全攻略
mysql·面试·性能优化
用户852495071841 天前
从零搭建自定义 MCP Server:打造你的专属工具服务
面试
黄敬峰1 天前
远程 MCP 实战:LangChain 同时接入高德地图、Chrome、文件系统,让 AI Agent 操控真实世界
面试
KaifuZeng1 天前
通信与接口协议面试问题汇总三
单片机·嵌入式硬件·面试·通信与接口协议
胡萝卜术1 天前
从聊天模型到本地执行助手:Remote MCP 多工具 Agent 实战
面试·架构·github