Kotlin
协程
编写挂起函数

编写挂起函数

默认顺序

当需要按顺序调用挂起函数时,可以直接顺序书写来调用它们

fun main() = runBlocking {
    val time = measureTimeMillis {
        doSomethingUsefulOne()
        doSomethingUsefulTwo()
    }
    println(time)
}

使用 async 并发

可以使用async函数使得任务并发执行,它在概念上与launch类似,但不同之处在于launch返回一个Job并且不携带任何结果,而async返回了一个Deferred,一个轻量级非阻塞的future,可以使用await来获取它的执行结果,但Deferred也是一个Job,可以和Job一样被控制

runBlocking {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulTwo() }
        val two = async { doSomethingUsefulTwo() }
        "result is ${one.await() + two.await()}"
    }
}

惰性启动 async

可以设置协程的start参数为LAZY,从而使得async变为惰性

只有当获取async值或者调用start方法时,async的结果才会被计算

但如果直接调用await输出值,将会导致async顺序执行,因为await将启动协程并等待其完成

val time = measureTimeMillis {
    val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
    val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
    one.start()
    two.start()
    println("result = ${one.await() + two.await()}")
}

异步风格的函数

这种风格是其它语言中的风格,不建议在Kotlin中这样使用

可以使用异步协程构建器定义异步调用的异步风格函数,并使用GlobalScope来取消结构化并发,使用..Async后缀来定义这种函数,以强调它们仅仅是用于启动异步计算

@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulTwoAsync() = GlobalScope.async {
    doSomethingUsefulOne()
}
 
@OptIn(DelicateCoroutinesApi::class)
fun somethingUsefulOneAsync() = GlobalScope.async {
    doSomethingUsefulTwo()
}

GlobalScope是一个精密的 API,在调用它时,很容易导致意外创建资源或者内存泄漏的问题,要使用它需要加上@OptIn(DelicateCoroutinesApi::class)注解