Kotlin Channel 开箱即用

创建 & 容量/溢出

ini 复制代码
val ch = Channel<T>(
  capacity = Channel.BUFFERED,                 // 0(RENDEZVOUS) | BUFFERED(~64) | UNLIMITED | CONFLATED | N
  onBufferOverflow = BufferOverflow.SUSPEND    // SUSPEND | DROP_OLDEST | DROP_LATEST
)
  • RENDEZVOUS(0) :无缓冲,强背压;BUFFERED :小缓冲常用;UNLIMITED :慎用,易 OOM;CONFLATED:只保最新。
  • 选型:必达→SUSPEND只要最新→CONFLATED / DROP_OLDEST滑窗→N+DROP_OLDEST

发送 / 接收

kotlin 复制代码
suspend fun SendChannel<T>.send(x)         // 可能挂起(形成背压)
fun    SendChannel<T>.trySend(x)           // 非挂起,失败立即返回

suspend fun ReceiveChannel<T>.receive()    // 队列空会挂起
fun    ReceiveChannel<T>.tryReceive()      // 非挂起
for (e in ch) { /* 读到 close 且队列清空时自然结束 */ }

小技巧:先非阻塞、失败再挂起

kotlin 复制代码
suspend fun <T> SendChannel<T>.offerOrSend(x: T) {
  if (!trySend(x).isSuccess) send(x)
}

关闭 / 取消

  • close(cause?):不再接收新元素;已入队会被读完后结束(优雅收尾)。
  • cancel(cause?):立即终止,可能丢未读(紧急停机)。
  • 接收安全模板:
kotlin 复制代码
while (true) when (val r = ch.receiveCatching()) {
  is ChannelResult.Success -> handle(r.getOrNull()!!)
  is ChannelResult.Closed  -> break
}

常用并发模式

  • pipeline:多段 Channel 串联;每段容量=节流阀;重段可开 N 个 worker。
  • fan-in :多生产者→单通道;由协调者统一 close
  • fan-out :单生产者→多消费者(单播/竞争消费);要广播请用 SharedFlow。
  • actor:把共享状态封进单协程(邮箱 Channel),串行处理,免锁。

与 Flow / SharedFlow 互通

  • Channel → Flow:receiveAsFlow()(保留通道) / consumeAsFlow()(收完就 cancel)。

  • Flow → Channel:produceIn(scope) 或 .onEach { ch.send(it) }.launchIn(scope)。

  • Flow → SharedFlow/StateFlow:shareIn(...) / stateIn(...)。

  • SharedFlow ↔ Channel:shared.produceIn(scope)、launch { for (e in ch) shared.emit(e) }。

取舍:强背压 & 单播 → Channel多播 & 状态(最新值)→ SharedFlow/StateFlow拉式流水线/按需计算 → Flow


时间与选择器(速率/超时/心跳)

scss 复制代码
withTimeoutOrNull(300) { ch.receive() }    // 接收超时→null
withTimeout(200) { ch.send(cmd) }          // 发送限时(SUSPEND 满会超时)
val tick = ticker(200, 0)                  // 周期节拍器(ReceiveChannel<Unit>)
select {                                   // 谁先就选谁
  ch.onReceive { process(it) }
  tick.onReceive { flush() }
  onTimeout(3000) { markStale() }
}

调优与守则(超精简)

  • 容量从 64 起步:过大→高延迟;过小→抖动。
  • 高频但可丢中间:DROP_OLDEST / CONFLATED ;必须逐条:SUSPEND/RENDEZVOUS
  • 给持资源元素配 onUndeliveredElement 做释放。
  • 正常收尾:生产者 close → 消费者读干净 ;紧急:cancel
  • 别用 UNLIMITED 掩盖压力;监控队列长度(自增自减计数打点)。

迷你示例:UI 只要最新 + 限频

scss 复制代码
val latest = Channel<State>(Channel.CONFLATED)
launch(Dispatchers.Default) {
  while (isActive) latest.trySend(snapshot())
}
launch(Dispatchers.Main) {
  latest.receiveAsFlow().sample(200).collect(::render)
}
相关推荐
前端一课1 小时前
第 28 题:async / await 的原理是什么?为什么说它是 Promise 的语法糖?(详细版)
前端·面试
前端一课1 小时前
第 28 题:手写 async/await(Generator 自动执行器原理)
前端·面试
前端一课1 小时前
第 33 题:浏览器渲染流程(Reflow 重排、Repaint 重绘、Composite 合成)*
前端·面试
前端一课1 小时前
前端面试第 34 题:事件循环(Event Loop)—— 必考高频题
前端·面试
前端一课1 小时前
第 26 题:Vue2 和 Vue3 的响应式原理有什么区别?为什么 Vue3 要用 Proxy 替代 defineProperty?
前端·面试
前端一课1 小时前
第 30 题:模块化原理(CommonJS vs ESModule)
前端·面试
前端一课1 小时前
第 31 题:Tree Shaking 原理与常见失效原因(高频 + 难点 + 面试必考)
前端·面试
前端一课1 小时前
第 27 题:Promise 实现原理(含手写 Promise)
前端·面试
前端一课1 小时前
第 32 题:深入理解事件循环(Event Loop)、微任务、宏任务(详细 + 难点 + 易错点)
前端·面试
前端一课1 小时前
【前端每天一题】🔥 第 25 题:什么是 Virtual DOM?它的优缺点是什么?Diff 算法是如何工作的?
前端·面试