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)
}
相关推荐
怕什么真理无穷8 小时前
C++面试4-线程同步
java·c++·面试
拉不动的猪11 小时前
# 关于初学者对于JS异步编程十大误区
前端·javascript·面试
熊猫钓鱼>_>13 小时前
Java面向对象核心面试技术考点深度解析
java·开发语言·面试·面向对象··class·oop
进击的野人15 小时前
CSS选择器与层叠机制
css·面试
T___T17 小时前
全方位解释 JavaScript 执行机制(从底层到实战)
前端·面试
9号达人17 小时前
普通公司对账系统的现实困境与解决方案
java·后端·面试
勤劳打代码18 小时前
条分缕析 —— 通过 Demo 深入浅出 Provider 原理
flutter·面试·dart
努力学算法的蒟蒻18 小时前
day10(11.7)——leetcode面试经典150
面试
进击的野人19 小时前
JavaScript 中的数组映射方法与面向对象特性深度解析
javascript·面试
南山安19 小时前
以腾讯面试题深度剖析JavaScript:从数组map方法到面向对象本质
javascript·面试