Kotlin协程使用async关键字仍串行执行问题排查咨询
问题原因
- 默认调度器限制:
runBlocking启动的协程默认继承当前调用线程作为调度器,属于单线程调度环境。你没有给async指定额外调度器的情况下,所有异步任务都会被调度到同一个线程执行,加上ActionReportGetter.getActions()是普通阻塞方法(非挂起函数),执行时会占用当前线程不释放,自然出现串行执行的效果。 - 事务绑定特性不影响协程调度逻辑:Spring事务确实是和线程绑定的,但是它不会改变协程的调度规则,你当前串行问题和事务无关,不过后续并行实现后要注意事务上下文传播的问题。
解决方案
- 给
async指定多线程调度器
IO密集型任务(比如含数据库查询、接口调用)指定Dispatchers.IO,CPU密集型计算指定Dispatchers.Default,即可实现多线程并行执行。 - 注意事务上下文适配
如果getActions()方法需要参与事务,由于子线程无法获取父线程的事务上下文,你需要给每个getActions()方法配置独立事务(比如Spring的@Transactional(propagation = Propagation.REQUIRES_NEW)),如果是只读逻辑不需要事务可以忽略该配置。
优化后代码示例
runBlocking { val actions = actionsReportGetters.map { actionReportGetter -> // 指定IO调度器实现多线程并行 async(Dispatchers.IO) { getActions(actionReportGetter, abstractUser) } }.awaitAll().flatten() allActions.addAll(actions) }
你也可以在suspend方法内部统一指定调度器,避免上层调用漏传调度器导致阻塞:
private suspend fun getActions(actionReportGetter: ActionReportGetter, traderUser: TraderUser): List<Action> { // 确保阻塞调用始终运行在IO调度器上,不会阻塞其他协程 return withContext(Dispatchers.IO) { actionReportGetter.getActions(traderUser) } }
内容的提问来源于stack exchange,提问作者Rory Towler
相关产品推荐
相关产品推荐

