Spring Boot非响应式环境下Kotlin协程无法并行执行问题
问题:Spring Boot非响应式环境下Kotlin协程无法并行执行
我正在使用Spring Boot和Kotlin构建后端应用,希望为特定方法实现并行执行。尝试使用协程后,底层方法仍同步执行。
实现代码:
fun getXsByIds(xIds: List<String>): List<X> { val xList = ArrayList<X>(); runBlocking { val promises = xIds.map { async { getXById(it) } }; xList.addAll((promises.awaitAll()).filterNotNull()) } return xList; } fun getXById(xId: String): X? { // 该方法向数据库发起请求 }
在getXById中添加日志后:
fun getXById(xId: String): X? { print("start"); // 该方法向数据库发起请求 print("end"); }
输出为:
start end start end start end ...
当前环境为Spring Boot非响应式,采用线程每请求(Thread per request)模式。请问为何协程无法并行执行?
原因分析
- runBlocking默认使用单线程上下文:runBlocking启动时默认绑定当前调用线程,内部所有协程(包括async创建的)都会在这个单线程的事件循环中执行,本质是串行调度,无法实现并行。
- getXById是阻塞式同步方法:该方法内部是阻塞的数据库请求,会占用当前线程直到操作完成,即使协程调度逻辑支持并行,单线程环境下也没有机会同时执行多个协程任务。
解决方案
要实现并行,需给协程指定多线程的Dispatcher,推荐使用Dispatchers.IO——它是专门为处理阻塞IO操作设计的线程池,适配数据库请求这类场景。
修改后的代码:
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking fun getXsByIds(xIds: List<String>): List<X> { val xList = ArrayList<X>() runBlocking { val promises = xIds.map { // 指定Dispatchers.IO作为协程上下文 async(Dispatchers.IO) { getXById(it) } } xList.addAll(promises.awaitAll().filterNotNull()) } return xList } fun getXById(xId: String): X? { print("start") // 数据库请求操作 print("end") }
修改后,每个async协程会被调度到Dispatchers.IO线程池的不同线程执行,阻塞的数据库请求会在多线程上并行处理,日志输出会呈现出并行执行的特征(比如start start start end end end)。
内容的提问来源于stack exchange,提问作者uzaysan
相关产品推荐
相关产品推荐

