Kotlin协程 -> 支持并发的channelFlow

ChannelFlow构建器详解

ChannelFlow vs Flow 核心差异

特性FlowChannelFlow
执行模式同步顺序异步并发
数据传输直接调用Channel缓冲 + emitAll
背压处理自然阻塞可配置策略
协程支持无内置作用域ProducerScope
适用场景简单数据流复杂并发场景

执行时序对比

Flow - 同步执行
flow {
    emit(1)    // 阻塞直到collector处理完
    emit(2)    // 阻塞直到collector处理完
}.collect { value ->
    println("收集: $value")
}
// 输出: 收集: 1 → 收集: 2 (严格顺序)
ChannelFlow - 并发执行
channelFlow {
    launch { send(1) }  // 并发发送
    launch { send(2) }  // 并发发送
}.collect { value ->
    println("收集: $value")
}
// 输出: 可能是 收集: 1 → 收集: 2 或 收集: 2 → 收集: 1

缓冲区配置策略

1. 无缓冲(默认)- RENDEZVOUS

channelFlow {  // capacity = 0
    send(1)    // 阻塞,直到有collector接收
    send(2)    // 阻塞,直到有collector接收
}
特点: 严格背压,生产者必须等待消费者

2. 有限缓冲

channelFlow(capacity = 10) {
    repeat(10) { send(it) }  // 前10个不阻塞
    send(10)                 // 第11个阻塞,等待缓冲区有空间
}
特点: 缓冲区满时阻塞

3. 无限缓冲

channelFlow(capacity = Channel.UNLIMITED) {
    repeat(1000) { send(it) }  // 全部不阻塞
}
特点: 永不阻塞,但可能内存溢出

4. 溢出策略配置

channelFlow(
    capacity = 10,
    onBufferOverflow = BufferOverflow.DROP_OLDEST
) {
    repeat(100) { send(it) }  // 不阻塞,丢弃旧数据
}

// 三种溢出策略:

// SUSPEND - 阻塞等待(默认)
// DROP_OLDEST - 丢弃最旧的数据
// DROP_LATEST - 丢弃最新的数据

send vs trySend 详解

send - 挂起函数(可能阻塞)

channelFlow {
    send(1)  // 挂起函数,缓冲区满时会阻塞协程
    send(2)  // 等待上一个发送完成或有空间
}
何时阻塞:

缓冲区满且溢出策略为 SUSPEND
无缓冲模式下没有消费者等待

trySend - 非阻塞函数

channelFlow {
    val result1 = trySend(1)  // 立即返回,不阻塞
    val result2 = trySend(2)  // 立即返回,不阻塞
    
    if (result1.isSuccess) {
        println("发送成功")
    } else {
        println("发送失败: ${result1.exceptionOrNull()}")
    }
}
返回结果:

ChannelResult.success(Unit) - 发送成功
ChannelResult.failure(exception) - 发送失败

实际应用场景对比

1. API并发请求

// ❌ Flow - 串行执行(慢)
fun fetchUsersFlow(ids: List<String>) = flow {
    ids.forEach { id ->
        emit(apiService.getUser(id))  // 一个接一个执行
    }
}

// ✅ ChannelFlow - 并行执行(快)
fun fetchUsersChannelFlow(ids: List<String>) = channelFlow {
    ids.forEach { id ->
        launch {
            send(apiService.getUser(id))  // 同时执行多个请求
        }
    }
}

2. 高频数据处理

// 传感器数据 - 使用trySend避免阻塞
fun sensorFlow() = channelFlow<SensorData>(
    capacity = 100,
    onBufferOverflow = BufferOverflow.DROP_OLDEST
) {
    sensorManager.registerListener(object : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent) {
            // 高频数据,使用trySend避免阻塞传感器线程
            trySend(SensorData(event.values, event.timestamp))
        }
    }, sensor, SensorManager.SENSOR_DELAY_FASTEST)
}

3. 网络回调处理

// WebSocket消息 - 回调中使用trySend
fun webSocketFlow() = channelFlow<String> {
    val webSocket = client.newWebSocket(request, object : WebSocketListener() {
        override fun onMessage(webSocket: WebSocket, text: String) {
            // 回调中使用trySend,避免阻塞网络线程
            trySend(text)
        }
    })
    
    awaitClose { webSocket.close(1000, "Flow closed") }
}

阻塞与非阻塞场景分析

阻塞场景(使用send

channelFlow {
    // 场景1: 无缓冲,消费者慢
    send(1)  // 阻塞直到消费者处理完
    
    // 场景2: 缓冲区满
    repeat(100) { send(it) }  // 超过capacity时阻塞
    
    // 场景3: 溢出策略为SUSPEND
    send(data)  // 缓冲区满时挂起等待
}

非阻塞场景(使用trySend

channelFlow {
    // 场景1: 有缓冲空间
    trySend(1)  // 立即返回成功
    
    // 场景2: 缓冲区满但使用trySend
    val result = trySend(2)  // 立即返回失败,不阻塞
    
    // 场景3: 溢出策略为DROP_*
    trySend(3)  // 根据策略丢弃数据,不阻塞
}

总结

  • 简单顺序流 → 使用 flow
  • 并发复杂流 → 使用 channelFlow
  • 关键数据 → 使用 send(可阻塞)
  • 高频数据 → 使用 trySend(非阻塞)
  • 合理配置缓冲区 → 根据数据特性选择capacity和溢出策略
    阻塞规律:
  • send + 缓冲区满 + SUSPEND策略 = 阻塞
  • trySend + 任何情况 = 不阻塞
  • 无缓冲模式下,send总是阻塞直到有消费者
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值