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")
}
其中:
runBlocking
,launch
, 及async
是最常被使用的 coroutine builder。- coroutine builder 後面跟著的就是我們撰寫的 suspending lambda,可以視為 coroutine 的進入點。
- 通常在 suspending lambda 裡會再呼叫其他 suspending function,例如
sendEmailSuspending
。 delay
,Job.join
,Deferred.await
則是用來等待的 high-level API。
High-level API
範例中的 async/await 並不是目前唯一支援的 concurrency pattern,目前看到正在開發中的還有:
- Golang 的 channel/select
- Python 的 generator/yield
- Erlang 或 Scala 的 Actor
- Java 的 Reactor
Low-level API
所有的 coroutine 機制都是基於底層的 low-level API 來實現的。之後有時間的話會再研究並分享 high-level API 是如何用 low-level API 來實現的。