Kotlin协程 async 和 withContext
2024-02-27 本文已影响0人
thishejue
async和withContext都可以返回耗时任务的执行结果。
- 多个 async 任务是并行的,async 返回的是一个Deferred<T>,需要调用await()方法获取结果。
- 多个 withContext 任务是串行的, 且withContext 可直接返回耗时任务的结果。
例1
先来看下在协程内,用普通的方式,计算两数之和,并统计所需时间。
fun test() = runBlocking {
val time = measureTimeMillis {
val ds1 = doSomething1()
val ds2 = doSomething2()
println("The result is ${ds1 + ds2}")
}
println("time is $time ms")
}
suspend fun doSomething1(): Int {
delay(1000)
return 5
}
suspend fun doSomething2(): Int {
delay(1000)
return 6
}
输出:
The result is 11
time is 2019 ms
分析:
因为doSomething1()和doSomething2()是顺序进行,所有时间为2019ms,接近2000ms。
例2
现在,使用async和await,再来看下。
fun test() = runBlocking {
val time = measureTimeMillis {
val ds1 = async { doSomething1() }
val ds2 = async { doSomething2() }
val r1 = ds1.await()
val r2 = ds2.await()
println("The result is ${r1 + r2}")
}
println("time is $time ms")
}
suspend fun doSomething1(): Int {
delay(1000)
return 5
}
suspend fun doSomething2(): Int {
delay(1000)
return 6
}
输出:
The result is 11
time is 1027 ms
分析:
计算结果仍然正确,但所需时间只要约1000ms。可见两者是并发的。所以,async是类似launch的,可以实现并发的执行任务,但是launch不会返回结果。
例3
在加上CoroutineStart启动方式(CoroutineStart.LAZY)
fun test() = runBlocking {
val time = measureTimeMillis {
val ds1 = async(start = CoroutineStart.LAZY) { doSomething1() }
val ds2 = async(start = CoroutineStart.LAZY) { doSomething2() }
// 如果立即都start了,那结果(时间消化)类似例2
// ds1.start()
// ds2.start()
// 如果之前没有start,那会等到调用await时候才启动,这样又类似顺序执行了
val r1 = ds1.await()
val r2 = ds2.await()
println("The result is ${r1 + r2}")
}
println("time is $time ms")
}
输出:
The result is 11
time is 2018 ms
分析:
在CoroutineStart.LAZY启动方式下,async会等到start或者await才启动。如上,之前如果没有start,那只有等到await,才启动,并且遇到第一个await便会阻塞。因此,所需的时间便是两者之和。
例4
现在使用withContext
fun test() = runBlocking {
val time = measureTimeMillis {
val r1 = withContext(Dispatchers.IO) {
println("at withContext1: ${getCurrentThread()}")
delay(1000)
5
}
val r2 = withContext(Dispatchers.IO) {
println("at withContext2: ${getCurrentThread()}")
delay(1000)
6
}
println("The result is ${r1 + r2}")
}
println("time is $time ms")
}
输出:
at withContext1: DefaultDispatcher-worker-1
at withContext2: DefaultDispatcher-worker-1
The result is 11
time is 2034 ms
分析:
可以看出两者是顺序执行的,耗时时间接近2000ms