美文网首页Kotlin
Kotlin协程组合挂起函数

Kotlin协程组合挂起函数

作者: 漆先生 | 来源:发表于2021-12-24 11:16 被阅读0次

一、默认顺序调用

在协程中的,挂起函数像常规的代码⼀样顺序都是默认的。

suspend fun doSomethingUsefulOne(): Int {
    delay(1000L)
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    delay(1000L)
    return 14
}

fun main() = runBlocking {
    val time = measureTimeMillis {
        val one = doSomethingUsefulOne()
        val two = doSomethingUsefulTwo()
        println("The answer is ${one + two}")
    }
    println("Completed in $time ms")
}

输出:
The answer is 27
Completed in 2042 ms

二、使用 async 并发

async 就类似于 launch。它启动了⼀个单独的协程,这是⼀个轻量级的线程并与其它所有的协程⼀起并发的工作。不同之处在于 launch 返回⼀个 Job 并且不附带任何结果值,而 async 返回⼀个 Deferred —— ⼀个轻量级的非阻塞 future,这代表了⼀个将会在稍后提供结果的 promise。你可以使用 .await() 在⼀个延期的值上得到它的最终结果,但是 Deferred 也是⼀个 Job ,所以如果需要的话,你可以取消它。

fun main() = runBlocking {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}
输出:
The answer is 27
Completed in 1022 ms

因为两个协程并发执行,速度快了两倍。请注意,使用协程进行并发总是显式的。

三、惰性启动的 async

async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。在这个模式下,只有结果 通过 await 获取的时候协程才会启动,或者在 Job 的 start 函数调用的时候。

fun main() = 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")
}
输出:
The answer is 27
Completed in 1028 ms

如果我们只是在 println 中调用 await,而没有在单独的协程中调用 start,这将会导致顺序行为,直到 await 启动该协程 执行并等待至它结束。

四、async风格的函数

使用 async 协程建造器并带有⼀个显式的 GlobalScope 引用。函数不是挂起函数,可以在任何地方使用,但是是异步执行。在kotlin中不推荐使用。

fun somethingUsefulOneAsync() = GlobalScope.async { doSomethingUsefulOne() }

五、使用 async 的结构化并发

由于 async 被定义为了 CoroutineScope 上 的扩展,我们需要将它写在作用域内,并且这是 coroutineScope 函数所提供的。

suspend fun concurrentSum(): Int = coroutineScope {
    val one = async {
        doSomethingUsefulOne()
    }
    val two = async {
        doSomethingUsefulTwo()
    }
    one.await() + two.await()
}

如果在 concurrentSum 函数内部发生了错误,并且它抛出了⼀个异常,所有在作用域中启动的协程都会被取消。

fun main() = runBlocking {
    try {
        println("The answer is ${failedConcurrentSum()}")
    } catch (e: ArithmeticException) {
        println("Computation failed with ArithmeticException")
    }
}

suspend fun failedConcurrentSum(): Int = coroutineScope {
    val one = async {
        try {
            delay(Long.MAX_VALUE)
            13
        } finally {
            println("First child was cancelled")
        }
    }
    val two = async {
        println("Second child throws an exception")
        throw ArithmeticException()
        14
    }
    one.await() + two.await()
}
输出:
Second child throws an exception
First child was cancelled
Computation failed with ArithmeticException

相关文章

网友评论

    本文标题:Kotlin协程组合挂起函数

    本文链接:https://www.haomeiwen.com/subject/qzhkqrtx.html