社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
首发于公众号: DSGtalk1989
通常情况下,协程中的挂起函数都是同步执行的,执行完一个执行另一个,我们举个例子,作如下的两种计算。
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // 假设我们在这里做了某些有用的工作
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // 假设我们在这里也做了某些有用的工作
return 29
}
fun main() = runBlocking<Unit> {
//sampleStart
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
}
println("Completed in $time ms")
//sampleEnd
}
这里出现了一个measureTimeMillis
方法,这个方法会返回一个long
,表示这个协程的消耗时间。最终打印是这样的。
The answer is 42
Completed in 2017 ms
这时候,如果我们希望两个任务是并发的,需要使用到async
。
我们写一个async{}
,然后点进去看一下。
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
跟之前展示的`launch`除了一个返回的是`Job`一个返回的是`Deferred`,其他是一模一样。进去一看
```js
/**
* Deferred value is a non-blocking cancellable future — it is a [Job] that has a result
*/
public interface Deferred<out T> : Job
是一个实现了Job
的接口,注释中说到是一个不会阻塞的,可以被取消的future
,是一个有结果的Job
。看上去可以在未来的某个时间点执行,而非立马执行的,且是异步的。
在Job
的基础上多了3个方法和一个属性。
public suspend fun await(): T
public val onAwait: SelectClause1<T>
public fun getCompleted(): T
public fun getCompletionExceptionOrNull(): Throwable?
下面两个都是实验性质的,我们就不看了主要是为了去拿异步协程的结果的。而现在本身可以直接通过await
也可以拿到结果。并且不会将协程再跑一遍。
我们对上面的部分代码略做改动,其他保持不变。
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
打印出来的结果是
The answer is 42
Completed in 1017 ms
很明显的两个挂起的函数变成了异步。
如果我们希望只有调用了await
方法才会开始启动协程,而不是在定义的时候就立马启动,可以针对async
方法传入start
参数CoroutineStart.LAZY
。
val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
// 执行某些计算
one.start() // 启动第一个协程
two.start() // 启动第二个协程
println("The answer is ${one.await() + two.await()}")
这样一来只会在调用了start
或者await
方法之后,整个协程才会启动。
一旦作用域中抛出了异常,一般情况下都会直接导致所有兄弟协程中断,以及等待的父协程中断。
但是使用全局作用域的协程并不会有中断问题,即使其中一个子协程抛出异常,其他的照跑不误。
suspend fun failedConcurrentSum(): Int = coroutineScope {
val one = async<Int> {
try {
delay(Long.MAX_VALUE) // 模拟一个长时间的计算过程
42
} finally {
println("First child was cancelled")
}
}
val two = async<Int> {
println("Second child throws an exception")
throw ArithmeticException()
}
one.await() + two.await()
}
打印出
Second child throws an exception
First child was cancelled
Kotlin学习笔记之 13 基础操作符run、with、let、also、apply
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!