Kotlin挂起函数调用Channel.send阻塞,无法获取Flow首个值求助
Kotlin挂起函数获取Flow首个值时send阻塞的原因
我编写了一个Kotlin挂起函数readSensorTemperature,目的是获取Flow的第一个值并返回,但程序在执行ch.send(st)时发生阻塞。相关代码如下:
private suspend fun readSensorTemperature(): Double { val ch = Channel<Double>() val job = coroutineScope { launch { myFlow.collect { st -> ch.send(st) } } } val res = ch.receive() job.cancel() return res }
(注:原代码中st -为笔误,已修正为st ->)
问题原因分析
核心问题是协程作用域的等待逻辑导致了死锁:
coroutineScope的特性是必须等待所有子协程执行完成后,才会继续执行后续代码。而子协程内的myFlow.collect是持续收集Flow数据的操作(除非Flow主动结束),这就导致主协程一直卡在coroutineScope调用处,永远走不到ch.receive()这一步。- 默认的
Channel是无缓冲的,ch.send(st)会挂起,直到有其他协程调用ch.receive()接收数据。现在子协程卡在send等待接收方,主协程卡在coroutineScope等待子协程结束,形成互相阻塞的死锁。
正确实现方式
Flow本身提供了first()操作符,可以直接获取第一个发射的值,完全不需要手动用Channel实现:
private suspend fun readSensorTemperature(): Double { return myFlow.first() }
如果一定要手动实现类似逻辑,需要避免coroutineScope的等待,直接启动子协程即可:
private suspend fun readSensorTemperature(): Double { val ch = Channel<Double>() val job = launch { try { myFlow.collect { st -> ch.send(st) // 拿到第一个值后停止收集 return@collect } } finally { ch.close() } } val res = ch.receive() job.cancel() return res }
内容的提问来源于stack exchange,提问作者Solvek
相关产品推荐
相关产品推荐

