Kotlin协程调用Thread.sleep()无法并行执行的问题解决
Kotlin协程并行执行问题解决
问题描述
作为Kotlin协程初学者,编写了一个尝试并行执行的示例,但代码未按预期并行运行。需求如下:
- 改造
sleepTwoSec()方法,使其在launch{...}中调用时实现并行执行 - 无需返回值(即发即弃),但
launchMultipleParallelFuns()需等待所有launch启动的任务完成后再退出
原代码如下:
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import java.lang.Thread.sleep import kotlin.time.measureTime fun main() { println("main start") println(measureTime { blockingFunction() }) println("main end") } fun blockingFunction() = runBlocking { println(" start blockingFunction") launchMultipleParallelFuns() println(" end blockingFunction") } suspend fun launchMultipleParallelFuns() = coroutineScope { println(" start launchMultipleParallelFuns") launch { sleepTwoSec(1) } launch { sleepTwoSec(2) } launch { sleepTwoSec(3) } launch { sleepTwoSec(4) } println(" end launchMultipleParallelFuns") } fun sleepTwoSec(n: Int) { println(" start sleepTwoSec $n") sleep(2000) println(" end sleepTwoSec $n") }
实际输出
main start start blockingFunction start launchMultipleParallelFuns end launchMultipleParallelFuns start sleepTwoSec 1 end sleepTwoSec 1 start sleepTwoSec 2 end sleepTwoSec 2 start sleepTwoSec 3 end sleepTwoSec 3 start sleepTwoSec 4 end sleepTwoSec 4 // 无并行执行 end blockingFunction 8.135047100s // 总耗时约8秒,无并行 main end
预期输出
main start start blockingFunction start launchMultipleParallelFuns end launchMultipleParallelFuns // 符合预期 start sleepTwoSec 1 // 所有任务同时启动 start sleepTwoSec 2 start sleepTwoSec 3 start sleepTwoSec 4 end sleepTwoSec 1 end sleepTwoSec 2 end sleepTwoSec 3 end sleepTwoSec 4 end blockingFunction 2s // 总耗时约2秒 main end
尝试过的无效修改
曾尝试用suspendCoroutine将sleepTwoSec改为挂起函数,但结果依旧:
suspend fun sleepTwoSec(n: Int) = suspendCoroutine { println(" start sleepTwoSec $n") sleep(2000) println(" end sleepTwoSec $n") it.resume(Unit) }
问题原因
Thread.sleep(2000)是阻塞式操作,会占用当前线程的执行时间片,协程调度器无法切换到其他协程执行- 即使将方法改为挂起函数,内部仍调用阻塞的
sleep,依旧会阻塞协程所在的线程,导致所有launch任务串行执行
解决方案
有两种可行方案,核心都是避免阻塞协程调度线程:
方案1:使用协程非阻塞挂起函数delay()
直接替换Thread.sleep()为Kotlin协程提供的delay(),这是一个非阻塞的挂起函数,会释放线程让其他协程执行:
import kotlinx.coroutines.delay suspend fun sleepTwoSec(n: Int) { println(" start sleepTwoSec $n") delay(2000) // 非阻塞挂起 println(" end sleepTwoSec $n") }
方案2:将阻塞操作放到IO调度器执行
如果必须使用阻塞的sleep(或其他阻塞IO操作),可以用withContext(Dispatchers.IO)将任务切换到IO线程池执行,避免阻塞主线程/协程调度线程:
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext suspend fun sleepTwoSec(n: Int) = withContext(Dispatchers.IO) { println(" start sleepTwoSec $n") sleep(2000) // 阻塞操作在IO线程执行 println(" end sleepTwoSec $n") }
修改后的完整代码(以方案1为例)
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlin.time.measureTime fun main() { println("main start") println(measureTime { blockingFunction() }) println("main end") } fun blockingFunction() = runBlocking { println(" start blockingFunction") launchMultipleParallelFuns() println(" end blockingFunction") } suspend fun launchMultipleParallelFuns() = coroutineScope { println(" start launchMultipleParallelFuns") launch { sleepTwoSec(1) } launch { sleepTwoSec(2) } launch { sleepTwoSec(3) } launch { sleepTwoSec(4) } println(" end launchMultipleParallelFuns") } suspend fun sleepTwoSec(n: Int) { println(" start sleepTwoSec $n") delay(2000) println(" end sleepTwoSec $n") }
验证结果
修改后执行输出符合预期,总耗时约2秒,所有sleepTwoSec任务并行启动并执行。
内容的提问来源于stack exchange,提问作者Irina S.
相关产品推荐
相关产品推荐

