并行启动协程:async
在前面的章节已经讲解了启动协程的两种方式,一种是通过 launch 函数,一种是在协程内部通过挂起函数。
比如要启动两个并行执行的协程,可以开启两个协程:
scope.launch(Dispatchers.IO) {}
scope.launch(Dispatchers.IO) {}
如果想让两个不同线程的代码按顺序执行,那就启动一个协程然后在协程内部配合挂起函数串行切线程:
private fun coroutineStyle() = lifecycleScope.launch {
val contributors = gitHub.contributors("square", "retrofit")
showContributors(contributos)
}
如果我们希望让两个请求在它们都返回了之后,把它们的结果合并,然后再把合并的结果显示在界面里。我们尝试下用挂起函数看行不行:
private fun coroutineStyle() = lifecycleScope.launch {
// 虽然最终是能拿到合并结果,但它们是串行执行的
// 即返回了 contributors1 后再执行请求获取 contributors2 的请求
val contributors1 = gitHub.contributors("square", "retrofit")
val contributors2 = gitHub.contributors("square", "okhttp")
showContributors(contributos1 + contributors2)
}
用上面的挂起函数虽然能满足我们拿到合并的结果,但是两个请求是串行执行的,这两个请求没有任何依赖关系,完全可以一起同时启动执行却要等待对方,这样就会导致网络耗时的翻倍。
那有什么方式可以让两个网络请求同时执行,也能做到最终将结果合并呢?
协程除了提供 launch 启动协程外,其实还提供了 async 函数,通过它可以并行启动协程:
private fun coroutineStyle() = lifecycleScope.launch {
// 这里包一层 coroutineScope 只是为了结构化并发异常管理提供方便
coroutineScope {
val contributors1 = async { gitHub.contributors("square", "retrofit") }
val contributors2 = async { gitHub.contributors("square", "okhttp") }
showContributors(contributos1.await() + contributors2.await())
}
}
使用 async 函数可以启动协程并行执行,最后通过 await 函数等待结果。
我们可以看下 async 函数是有返回值返回的,类型为 Deferred:
Builders.common.kt
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T // 有返回值
): Deferred<T> {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyDeferredCoroutine(newContext, block) else
DeferredCoroutine<T>(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
协程之间互相等待:join
除了 async 之外,如果你只是希望两个并行流程在顺序上有某种依赖而不依赖结果,可以用 join 函数,可以做到协程之间互相等待:
scope.launch {
val initJob = launch { init () }
val contributors = gitHub.contributors("square", "retrofit")
// processData 依赖 init 的执行结束,用 join 等待执行结束后再继续
initJob.join()
processData()
}
总结
-
启动协程有两个函数:launch 和 async,async 可以并行启动协程,最后通过 await 等待结果返回,常用于多个处理同时执行后合并结果的操作
-
如果你只是希望两个并行流程在顺序上有某种依赖而不依赖结果,可以用 join 函数,可以做到协程之间互相等待