Kotlin之witchContext与launch以及async的区别

·  阅读 2391
Kotlin之witchContext与launch以及async的区别

前言

在使用协程的过程中,有几个不同的启动协程的函数,分别适用于不同的场景。主要包括withContextlaunchasync,这篇文章主要是通过一个例子来看看这几个协程启动函数的区别,每一个函数都有其使用的场景,可以根据要实现的目标来选择到底应该使用哪个函数。

launch

lauch是最常见的启动一个协程的方法,可以通过GlobalScope.launch开启一个全局生命周期的协程,也可以通过CoroutineScope(CoroutineContext).launch 来开启一个在指定的 CoroutneContext 范围的协程。也可以记录这个Job并通过Job.cancel()随时取消。首先看下面的例子:

fun main(args: Array<String>) {
    println("main")
    testLaunch()
    Thread.sleep(2000)
}


fun testLaunch() {
    GlobalScope.launch {
        func1()
    }

    GlobalScope.launch {
        func2()
    }
}

suspend fun func1() {
    delay(1500)
    println("func1")
}

suspend fun func2() {
    delay(300)
    println("func2")
}
复制代码

在上面的例子中,func2执行时间要快于func1,通过启动两个协程来看一下两个函数的执行顺序。使用launch不会阻塞主线程,但是由于launch不是一个suspend函数,所以同时也不会等待协程的返回结果。

输出:

before
func2
func1
after
复制代码

根据输出可以看到,launch并不会等待当前协程的执行结果,所以launch适用于一些不需要等待返回的函数,或者可以通过回调的方式,当获取到结果的时候执行一些操作。

withContext

接下来看看withContext,将上述例子换成withContext,来看看和使用launch会有什么不同:

fun testWithContext() {
    GlobalScope.launch {
        func1WithContext()
        func2WithContext()
    }
}

suspend fun func1WithContext() = withContext(Dispatchers.IO) {
    delay(1500)
    println("func1")
}

suspend fun func2WithContext() = withContext(Dispatchers.IO) {
    delay(300)
    println("func2")
}
复制代码

输出:

before
func1
func2
after
复制代码

通过输出可以看到,func1WithContextfunc2WithContext是顺序执行的。由于withContextsuspend函数,所以协程执行到这里会挂起直到该函数完成。withContext需要传入一个调度器的参数,指定协程运行在哪个线程。

可以看出来,当需要等待函数的执行结果时可以使用withContextwithContext会等待结果返回并且不会阻塞主线程。但这里有一个问题,假如在同一个协程内,有多个耗时任务,但是相互之前并没有逻辑关系,这时使用withContext使得所有任务串行是低效的。那么有没有一种方式是可以并行执行多个任务,但又会等待所有任务的返回结果呢?来看看下面的async

async:

我们将例子修改为使用async看看执行结果,简单修改一下函数,两个函数分别返回一个值,最后来计算两个函数返回值的和:

fun testAsync() {
    GlobalScope.launch {
        val deferred1 = async(Dispatchers.IO) { func1Async() }
        val deferred2 = async(Dispatchers.IO){ func2Async() }
        val result = deferred1.await() + deferred2.await()
        println("the sum is: $result" )
    }
}

suspend fun func1Async(): Int {
    delay(1500)
    println("func1")
    return 1
}

suspend fun func2Async(): Int {
    delay(300)
    println("func2")
    return 2
}
复制代码

输出:

before
func2
func1
the sum is: 3
after
复制代码

通过上面的输出可以看到,func2Asyncfunc1Async更快执行,说明两个函数是并行的。但是最后的结果是正确的,这就是async的作用。可**以看到async返回的是Deferred<T>Deferred<T>表示一个非阻塞的课取消的值,继承自Job。**看例子中最后使用到了deferred1.await() + deferred2.await(),就表示需要等待两个async的值都返回才会执行,**其中await()其实就是一个suspend函数。**当不使用await()的时候,asynclaunch 的效果是一样的。还有一点需要注意的是await的调用时机,如果把上述例子改为:

val deferred1 = async(Dispatchers.IO) { func1Async() }.await()
val deferred2 = async(Dispatchers.IO){ func2Async() }.await()
val result = deferred1 + deferred2
复制代码

如果这样调用作用就与withContext一样了。协程会阻塞直到func1Async()执行完成才会执行func2Async()

可以看到,async适用于多个并行任务但又需要等待结果的情况

总结

  • launch
    • 不会阻塞直到结果返回
    • 不会阻塞线程
    • 并行执行
  • withContext:
    • 会阻塞当前协程直到函数返回
    • 从指定的Dispatcher执行函数
    • 当执行函数的时候不会阻塞线程
    • 串行执行
  • async
    • 当使用awiat函数时,会阻塞直到结果返回
    • 如果不使用await,其效果与launch一样
    • 适用于多个并行任务但需要等待结果返回情形
    • 并行执行

顺便打个广告,猿辅导研发招聘各岗位,有大量HC。感兴趣的话可以简历发我的邮箱哦:fb0122@163.com。欢迎各位大佬来撩~ 😜 😜

分类:
Android
标签:
分类:
Android
标签:
收藏成功!
已添加到「」, 点击更改