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)
}
相关推荐
LYFlied3 小时前
【每日算法】LeetCode 70. 爬楼梯:从递归到动态规划的思维演进
算法·leetcode·面试·职场和发展·动态规划
YoungHong19923 小时前
面试经典150题[073]:从中序与后序遍历序列构造二叉树(LeetCode 106)
leetcode·面试·职场和发展
regon3 小时前
第九章 述职11 交叉面试
面试·职场和发展·《打造卓越团队》
LYFlied3 小时前
【每日算法】LeetCode 105. 从前序与中序遍历序列构造二叉树
数据结构·算法·leetcode·面试·职场和发展
gis分享者4 小时前
如何在 Shell 脚本中如何使用条件判断语句?(中等)
面试·shell·脚本·语法·使用·判断·条件
LYFlied5 小时前
【每日算法】LeetCode 114. 二叉树展开为链表:从树结构到线性结构的优雅转换
数据结构·算法·leetcode·链表·面试·职场和发展
Q741_1475 小时前
Linux 进程核心解析 fork()详解 多进程的创建与回收 C++
linux·c++·面试·笔试·进程
牛客企业服务5 小时前
AI面试:如何从概念真正落地?
人工智能·面试·职场和发展
铭哥的编程日记5 小时前
后端面试通关笔记:从真题到思路(me)
笔记·面试·职场和发展
写写闲篇儿14 小时前
微软面试之白板做题
面试·职场和发展