Kotlin协程的第一步

异步编程正在获得动力,因为它允许更有效地利用处理器时间。因此,应用程序可以在每单位时间内处理更多请求,并且可以更好地扩展。

目前,实现异步方法有几个选项:

  1. 回调
  2. 反应式编程
  3. 协程

协程

协程允许您将应用程序代码保持其通常形式,执行在后台任务之间切换的所有操作。

suspend fun doSomething(arg: Argument) {
    val firstValue = sendRequest(arg)
    val secondValue = sendAnotherRequest(firstValue)
}

在示例中,我们用 suspend 关键字标记 doSomething 函数,这意味着它的答案不会立即出现。该函数本身还一个接一个地执行一些异步请求。

从常规函数调用挂起函数

不能从常规函数调用挂起函数,因为 JVM 不清楚应在哪个线程上执行该函数。

如果我们想在同一线程上执行一个函数,我们可以使用 runBlocking。当然,此选项将不允许我们有效地利用CPU资源。但它可以在测试或命令行界面中使用。

fun casualFunction() {
    runBlocking { suspendFunction() }
}

fun suspend suspendFunction() {
    doSomething()
}

另一种方法是使用单独的线程池。下面的示例使用 Dispatchers.IO,默认为 max(64, number of cores)但您可以设置自定义线程池。

fun casualFunction() {
    CoroutineScope(Dispatchers.IO).launch {
        delay(1000)
        println("Launch finished")
    }
    println("Casual function finished")
}

重要的是要了解对启动块的调用将发生在不同的线程中,并且该方法将继续执行,因此Casual function finished将首先打印出来。

在挂起函数内运行阻塞操作

如果我们需要在挂起函数中运行繁重的函数(例如 IO 操作),该怎么办?如果我们只是运行它,它将阻塞当前线程,并且可能会破坏异步编程的整个想法。

相反,我们可以为慢速操作定义一个单独的上下文,以免阻塞现有线程。

suspend fun suspendFunction() {
    val context = Executors.newFixedThreadPool(10).asCoroutineDispatcher()

    withContext(context) {
        runSomethingSlow()
    }
}

现在,外部调度程序将挂起并将控件委托给我们的自定义上下文。完成后,自定义上下文会将控件返回到外部调度程序。