16-异步并发执行
12.4.2 异步并发执行
如果两个挂起函数之间没有时序上的依赖关系,而且希望通过并发地执行这两个函数来提高执行效率,还可以使用异步的方式来执行。使用异步方式调用时,会用到一个异步函数async,它位于kotlinx.coroutines库中。
fun <T> async(block: suspend () -> T)
严格来说,async只是一个普通函数而不是挂起函数,但是它的block参数带有一个suspend修饰的函数类型suspend () -> T。因此,当将一个Lambda表达式传给async函数时,它需要一个挂起Lambda表达式。代码如下。
async {
doSomething(foo)
…
}
从概念上来讲,async函数与launch函数一样,都可以启动一个单独的协程。不同的是,launch函数返回一个不含任何结果的值,而async函数返回一个延迟任务对象Deferred,一种轻量级非阻塞的Future,它表示会在后面提供结果值,可以使用await函数来获取具体的返回结果。
fun main(args: Array<String>) = runBlocking{
val time = measureTimeMillis {
//使用async()异步协程
val one = async(CommonPool) { asynOne() }
val two = async(CommonPool) { asynTwo() }
//使用await()获取协程返回值
println("result is ${one.await() + two.await()}")
}
println("Total time is ${time}")
}
suspend fun asynOne(): Int {
delay(1000)
return 3
}
suspend fun asynTwo(): Int {
delay(2000)
return 5
}
运行上面的代码,输出的结果如下。
result is 8
Total time is 2022
可以发现,执行两个相同的挂起函数时,异步并发方式比传统的顺序执行效率更高。Deferred接口定义如下。
public interface Deferred<out T> : Job {
val isCompletedExceptionally: Boolean
val isCancelled: Boolean
public suspend fun await(): T
public fun <R> registerSelectAwait(select: SelectInstance<R>, block: suspend (T) -> R)
public fun getCompleted(): T
@Deprecated(message = "Use `isActive`", replaceWith = ReplaceWith("isActive"))
public val isComputing: Boolean get() = isActive
}
延迟任务Deferred对象属于Job类型,它继承自Job,具有isCompleted、isActive等属性和join、cancel等函数。当然也可以在需要时直接取消它,其中,Deferred对象的常见属性和函数说明如下。
- isCompletedExceptionally:当协程在计算过程中出现异常failed或被取消时,返回true,此时isActive为false,isCompleted为true。
- isCancelled:如果当前延迟任务被取消,返回true;否则返回false。
- await:等待延迟任务完成,如果延迟任务完成,则返回结果值或者相应的异常。
在这当中,延迟任务对象Deferred的状态与对应的属性值如表12-3所示。
| 状态 | isActive | isCompleted | isCompletedExceptionally | isCancelled | | :----- | :----- | :----- | :----- | :----- | :----- | :----- | | New | false | false | false | false | | Active | true | false | false | false | | Resolved | false | true | false | false | | Failed | false | true | true | false | | Cancelled | false | true | true | true |
除此之外,async函数还提供了一个懒加载的选项CoroutineStart.LAYZ参数,该参数表示等待await执行或者启动函数被调用。