github原文地址
原创翻译,转载请保留或注明出处:https://www.jianshu.com/p/e0ad1e9fc32a
编写挂起函数
本节涵盖了编写挂起函数的各种方式
默认按顺序
假设我们有两个定义好的挂起函数,这些函数做一些有用的事比如远程调用、计算之类。我们只是假设它们是有用的,但实际上为了这个示例的目的,每个函数内只是延迟了一秒钟:
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // pretend we are doing something useful here
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // pretend we are doing something useful here, too
return 29
}
如果我们需要按顺序调用它们,我们该怎么做——首先调用doSomethingUsefulOne
然后是doSomethingUsefulTwo
,并计算结果总和?在实践中,我们使用第一个函数的结果来决定是否调用第二个函数或如何调用它。
我们只是使用正常的顺序调用,因为协程中的代码与常规代码一样,默认情况下是连续的,以下示例通过测量执行两个挂起函数的总时间来演示:
fun main(args: Array<String>) = runBlocking<Unit> {
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
}
println("Completed in $time ms")
}
获取完整代码 here
输出如下:
The answer is 42
Completed in 2017 ms
并发使用异步
如果doSomethingUsefulOne
与doSomethingUsefulTwo
的调用之间不存在依赖关系,而且我们希望通过同时执行两者以更迅速的获取结果?这种情况下异步可以帮助你。
概念上,async 和 launch 很像。它开启了一个单独的协程,它是一个与所有其他协程同时工作的轻量级线程。区别在于launch
会返回一个个 Job 并且不会携带任何结果值,而async
会返回一个 Deferred ——这是一个轻量、非阻塞的future,表示它承诺会稍后提供结果。你可以在一个延迟值上使用.await()
用来获取其最终结果,但Deferred
也是一个Job
,因此如果需要你可以取消它。
fun main(args: Array<String>) = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
获取完整代码 here
输出如下:
The answer is 42
Completed in 1017 ms
可以看到速度是之前的两倍,因为我们同时执行了两个协程。请注意,协程的并发执行总是显式的。
延迟启动异步
async 存在一个延迟设置,具体使用:以 CoroutineStart.LAZY 为值设置可选参数start
。只有在它的结果被需要、await 和 start 被调用才会启动协程。运行以下示例,以区分在这个可选项下与前一个示例的不同:
fun main(args: Array<String>) = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
获取完整代码 here
输出如下:
The answer is 42
Completed in 2017 ms
所以我们回到顺序执行了,因为我们第一次启动并等待one
的结果,接着又启动并等待two
的结果,这并不是惰性的合理用例。当值的计算涉及挂起函数时,它是被设计为标准lazy
函数的替代品。
异步风格函数
我们可以使用异步协程构建器,来定义调用了doSomethingUsefulOne
和doSomethingUsefulTwo
的异步风格函数。使用Async
后缀命名这类函数是一种很好的风格,突出显示他们只启动异步计算的事实,并且需要使用得到的延迟值来获取结果。
// The result type of somethingUsefulOneAsync is Deferred<Int>
fun somethingUsefulOneAsync() = async {
doSomethingUsefulOne()
}
// The result type of somethingUsefulTwoAsync is Deferred<Int>
fun somethingUsefulTwoAsync() = async {
doSomethingUsefulTwo()
}
要注意一点,这些xxxAsync
函数不是挂起函数。他们可以在任何地方使用,然而他们的使用总是暗示他们的行为与调用者代码的异步(这里意味着并发)执行。
如下示例显示了他们在协程外的使用:
// note, that we don't have `runBlocking` to the right of `main` in this example
fun main(args: Array<String>) {
val time = measureTimeMillis {
// we can initiate async actions outside of a coroutine
val one = somethingUsefulOneAsync()
val two = somethingUsefulTwoAsync()
// but waiting for a result must involve either suspending or blocking.
// here we use `runBlocking { ... }` to block the main thread while waiting for the result
runBlocking {
println("The answer is ${one.await() + two.await()}")
}
}
println("Completed in $time ms")
}
获取完整代码 here
网友评论