一、前言
在之前的例子中,我们知道可以通过launch 或者async 来启动协程,并可以控制其生命周期,而且还知道了通过async 的异步可以做到并行运行。这里记录一下其它的操作
二、延迟启动协程
协程可以通过提前定义,然后当某一条件触发时候再进行启动,如下
private suspend fun doSomethingUsefulOne(): Int {
delay(1000L)
return 13
}
private suspend fun doSomethingUsefulTwo(): Int {
delay(1000L)
return 29
}
@Test
fun lazy(){
runBlocking {
val time = measureTimeMillis {
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()}")
}
println("Completed in $time ms")
}
}
对于延时启动的函数,可以使用Job.start() 或者Deffered.await() 来进行启动,不过这里的话先使用Job.start() 启动再使用Deffered.await() 来获取结果,因为这样才不会导致并行的程序因为await() 变成串行程序
三、GlobalScope.async
其实官方是不建议直接使用GlobalScope启动协程的因为不好控制。例如我们编写一个异步的任务(异步任务通常使用"…Async"的方式命名)。
- GlobalScope是一个微妙的 API,可能会以非平凡的方式适得其反,下面将解释其中一种方式,因此您必须明确选择使用
@OptIn(DelicateCoroutinesApi::class) 。
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulOneAsync() = GlobalScope.async {
doSomethingUsefulOne()
}
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulTwoAsync() = GlobalScope.async {
doSomethingUsefulTwo()
}
通过GlobalScope.async 启动的代码可以在任何地方执行异步操作,如下
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulOneAsync() = GlobalScope.async {
doSomethingUsefulOne()
}
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulTwoAsync() = GlobalScope.async {
doSomethingUsefulTwo()
}
@Test
fun taskAsync(){
runBlocking {
val time = measureTimeMillis {
val one = somethingUsefulOneAsync()
val two = somethingUsefulTwoAsync()
runBlocking {
println("The answer is ${one.await() + two.await()}")
}
}
println("Completed in $time ms")
}
}
这个代码本身没有问题,倘若出于某种原因协程要取消掉,比如出现异常,在val one = somethingUsefulOneAsync() 和one.await() 中间出现错误,那么即使明确调用了cancel() ,somethingUsefulOneAsync() 还是会在后台默默运行。这里可以使用coroutineScope 来解决这个问题。所以需要修改为以下方式
suspend fun concurrentSum(): Int = coroutineScope {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
one.await() + two.await()
}
@Test
fun taskAsync(){
runBlocking {
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")
}
}
这是因为coroutineScope 函数是个挂起函数在调用的地方需要跟使用它的作用域绑定,这样当作用域取消时,这个函数的内容也取消了。
四、参考链接
-
编写挂起函数 https://kotlinlang.org/docs/composing-suspending-functions.html#lazily-started-async
|