Android食用指南之父子协程和挂起函数(三)

769 阅读3分钟

Android 协程系列博客:

协程Coroutines基础知识(一)

协程的创建、取消与超时(二)

父子协程和挂起函数(三)

正如在第一篇文章中我们所说的,在一个协程里面调用多个挂起函数,这些函数默认是顺序执行的,当第一个函数执行完毕之后,第二个函数才开始执行。这在某种特殊需求场景的时,这种写法对于开发者而言是非常友好的,但大多数情况下,我们并不太关心这几个函数的执行顺序,只需要在所有函数执行完毕之后给我最终的结果,是不是有一种可以让这些函数并行执行以提高我们的运行效率呢?

很显然是有的。

我先定义了两个简单的挂起函数functionOne和functionTwo,如下:

private suspend fun functionOne(): Int {
    delay(2000)
    return 1
}

private suspend fun functionTwo(): Int {
    delay(2000)
    return 2
}

我们用普通的方式调用这两个挂起函数并打印方法的总耗时:

GlobalScope.launch {
    var costTime = measureTimeMillis {//我们引入这个函数来统计代码运行时间
        var resultOne = functionOne()
        var resultTwo = functionTwo()
        println("最终结果 ${resultOne + resultTwo}")
    }
    println("方法运行总耗时  $costTime ms")
}

image.png

当两个函数没有必要的先后顺序时,我们可以引入async并发函数来提高我们的运行速度:

GlobalScope.launch {
    var costTime = measureTimeMillis {
        var resultOne = async { functionOne() }
        var resultTwo = async { functionTwo() }
        println("最终结果 ${resultOne.await() + resultTwo.await()}")
     }
     println("方法运行总耗时  $costTime ms")
}

image.png

可以看出我们使用了async并发之后,效率有了明显的提高,我们查看一下async源码:

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
}

可以发现async通launch一样都是CoroutineScope的拓展函数,其作用也类似,都是开启一个新的协程,不同点就是block函数比launch的block函数多了一个泛型的返回值和async函数的返回值是一个Job的子类Deferred。这个Deferred和Java里面的Future类似,但Deferred是非阻塞的,更轻量。

不知你是否还记得上一章中我们介绍启动模式的时候说过这么一段话:

***LAZY****延迟启动协程,只在需要的时候启动*

如果再上面的例子里面,我们在使用async的时候传入该启动模式,那么在await被调用的时候,async里面的代码才真正开始执行,这就是懒加载的协程。

var result = async(start = CoroutineStart.LAZY) { functionOne() }
int resultValue = result.await()//这时候上面的协程代码块才开始运行

关于挂起函数的并发执行就先介绍这么多,接下来我们说一下什么是父子协程

在上面的例子中,我们通过GlobalScope.launch启动了一个协程,这个协程并没有父作业并且协程的作用域是全局的,是独立运作的,这个协程就是根协程。

然后我们在这个协程里面添加了两个async的代码块,async也是启动协程的一中方式,而这个新启动的协程是在GlobalScope.launch中的,launch就是async的父协程,async就是launch的子协程。

关于父子协程只需要记住以下三个概念:

1、当一个父协程被取消的时候,所有它的子协程也会被递归的取消。

2、父协程总是等待所有子进程执行结束,不显式的跟踪所有子协程的启动,并且不必使用 Job.join 在最后的时候等待它们。

3、如果一个子协程失败,则父协程和另外的子协程都会被取消。

以上就是本篇博客的全部内容,赶快上号试试吧~

image.png

如果该文章能够帮到你,欢迎点赞和评论,一起交流探讨~