runBlocking是否仅可用于测试和main函数?非对应场景该用什么替代?
可行的实现方案
你可以根据自己的应用后续演化计划、当前接口的签名约束选择以下任意一种方案:
方案1:完全不用协程,用Java标准库并发工具
如果你的应用暂时没有全面接入协程的计划,且需要保持process函数同步阻塞返回结果的签名不变,直接用JDK自带的线程池实现即可,完全不需要引入协程相关逻辑:
// 线程池全局复用,避免每次调用process都创建销毁线程的开销 private val computeExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) fun process(input: InputType): ResultType { val tasks = input.splitToList().map { item -> Callable { processItem(item) } } // 提交所有任务并等待全部执行完成,拿到结果列表 val itemResults = computeExecutor.invokeAll(tasks).map { it.get() } // 按你的业务逻辑把itemResults拼装为ResultType返回即可 return itemResults }
方案2:继续使用协程,合理使用runBlocking
官方文档提示runBlocking仅适合main函数和测试,核心限制场景是在已经处于协程环境的代码中调用runBlocking,这种情况会阻塞协程调度线程,引发线程饿死、性能下降的问题。
如果你的应用其他部分完全没有用到协程,runBlocking就是你这段并行逻辑唯一的协程入口,这种场景下用runBlocking不会有任何问题,完全可以正常使用。
如果后续应用会全面接入协程,你可以把函数改成suspend,用coroutineScope替换runBlocking即可:
suspend fun process(input: InputType): ResultType = coroutineScope { input.splitToList() .map { async(Dispatchers.Default) { processItem(it) } } .awaitAll() }
方案3:适配异步调用场景
如果上层调用逻辑可以接受异步返回结果,你可以用CompletableFuture实现非阻塞的并行计算:
fun processAsync(input: InputType): CompletableFuture<ResultType> { val futures = input.splitToList().map { item -> CompletableFuture.supplyAsync { processItem(item) } } return CompletableFuture.allOf(*futures.toTypedArray()) .thenApply { val itemResults = futures.map { it.join() } // 拼装为ResultType返回 itemResults } }
上层调用时可以选择添加异步回调,也可以按需调用join()/get()阻塞获取结果。
内容的提问来源于stack exchange,提问作者k314159
相关产品推荐
相关产品推荐

