Kotlin Coroutine 的架構

Kotlin 從 1.1 版開始實驗性地支援 coroutine,主要的目標是簡化非同步編程的複雜度。Diving deep into Kotlin Coroutines 解釋了 coroutine 跟一般常用的 callback 及目前蠻多人在用的 reactive 模式有何不同。

由於目前 kotlinx-coroutines-core 的實現包含了不同抽象程度的 API,初學者建議可以用下面這張圖來學習如何使用 Kotlin coroutine:

範例分析

套用下面這個範例來理解:

suspend fun sendEmail(r: String, msg: String): Boolean { // 3
    delay(2000) // 4
    println("Sent '$msg' to $r")
    return true
}

suspend fun getReceiverAddressFromDatabase(): String { // 3
    delay(1000) // 4
    return "[email protected]"
}

suspend fun sendEmailSuspending(): Boolean { // 3
    val msg = /* 1 */ async(CommonPool) { // 2
        delay(500)
        "The message content"
    }
    val recipient = /* 1 */ async(CommonPool) { // 2
        getReceiverAddressFromDatabase()
    }
    println("Waiting for email data")
    val sendStatus = /* 1 */ async(CommonPool) { // 2
        sendEmail(recipient.await(), msg.await()) // 4
    }
    return sendStatus.await()
}

fun main(args: Array<String>) = /* 1 */ runBlocking(CommonPool) {
    val job = /* 1 */ launch(CommonPool) { // 2
        sendEmailSuspending()
        println("Email sent successfully.")
    }
    job.join() // 4
    println("Finished")
}

其中:

  1. runBlocking, launch, 及 async 是最常被使用的 coroutine builder。
  2. coroutine builder 後面跟著的就是我們撰寫的 suspending lambda,可以視為 coroutine 的進入點。
  3. 通常在 suspending lambda 裡會再呼叫其他 suspending function,例如 sendEmailSuspending
  4. delay, Job.join, Deferred.await 則是用來等待的 high-level API。

High-level API

範例中的 async/await 並不是目前唯一支援的 concurrency pattern,目前看到正在開發中的還有:

Low-level API

所有的 coroutine 機制都是基於底層的 low-level API 來實現的。之後有時間的話會再研究並分享 high-level API 是如何用 low-level API 來實現的。