Kotlin 协程把 suspend 修饰符引入到了我们 Android 开发者的日常开发中。您是否好奇它的底层工作原理呢?编译器是如何转换我们的代码,使其能够挂起和恢复协程操作的呢?
了解这些将会帮您更好地理解挂起函数 (suspend function) 为什么只会在所有工作完成后才会返回,以及如何在不阻塞线程的情况下挂起代码。
本文概要: Kotlin 编译器将会为每个挂起函数创建一个状态机,这个状态机将为我们管理协程的操作!
???? 如果您是 Android 平台上协程的初学者,请查阅下面这些协程 codelab:
在 Android 应用中使用协程
https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#0
协程的进阶使用: Kotlin Flow 和 Live Data
https://codelabs.developers.google.com/codelabs/advanced-kotlin-coroutines/#0
协程 101
协程简化了 Android 平台的异步操作。正如官方文档《利用 Kotlin 协程提升应用性能》所介绍的,我们可以使用协程管理那些以往可能阻塞主线程或者让应用卡死的异步任务。
《利用 Kotlin 协程提升应用性能》
https://developer.android.google.cn/kotlin/coroutines
协程也可以帮我们用命令式代码替换那些基于回调的 API。例如,下面这段使用了回调的异步代码:
// 简化的只考虑了基础功能的代码
fun loginUser(userId: String, password: String, userResult: Callback<User>) {
// 异步回调
userRemoteDataSource.logUserIn { user ->
// 成功的网络请求
userLocalDataSource.logUserIn(user) { userDb ->
// 保存结果到数据库
userResult.success(userDb)
}
}
}
上面的回调可以通过使用协程转换为顺序调用:
suspend fun loginUser(userId: String, password: String): User {
val user = userRemoteDataSource.logUserIn(userId, password)
val userDb = userLocalDataSource.logUserIn(user)
return userDb
}
在后面这段代码中,我们为函数添加了 suspend 修饰符,它可以告诉编译器,该函数需要在协程中执行。作为开发者,您可以把挂起函数看作是普通函数,只不过它可能会在某些时刻挂起和恢复而已。
不同于回调,协程提供了一种简单的方式来实现线程间的切换以及对异常的处理。但是,在我们把一个函数写成挂起函数时,编译器在内部究竟做了什么事呢?
Suspend 的工作原理
回到 loginUser 挂起函数,注意它调用的另一个函数也是挂起函数:
suspend fun loginUser(userId: String, password: String): User {
val user = userRemoteDataSource.logUserIn(userId, password)
val userDb = userLocalDataSource.logUserIn(user)
return userDb
}
// UserRemoteDataSource.kt
suspend fun logUserIn(userId: String, password: String): User
// UserLocalDataSource.kt
suspend fun logUserIn(userId: String): UserDb
简而言之,Kotlin 编译器会把挂起函数使用有限状态机 (稍后讲到) 转换为一种优化版回调。也就是说,编译器会帮您实现这些回调!
有限状态机
https://en.wikipedia.org/wiki/Finite-state_machine
Continuation 接口
挂起函数通过 Continuation 对象在方法间互相通信。Continuation 其实只是一个具有泛型参数和一些额外信息的回调接口,稍后我们会看到,它会实例化挂起函数所生成的状态机。
Continuation
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/-continuation/index.html
Continuation