协程是什么?
协程并不是一个新的概念,它并不是 Kotlin 发明的。它们已经存在了几十年,并且在 Go 等其他一些编程语言中很受欢迎。
协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。协程更适合于用来实现彼此熟悉的程序组件,如协作式多任务、异常处理、事件循环、迭代器、无限列表和管道。
根据高德纳的说法, 马尔文·康威于1958年发明了术语“coroutine”并用于构建汇编程序.
本文主要讲协程在 Kotlin 中实现的方式。事实上,在 Kotlin 中除了 suspend 关键字,没有任何其他关键字被添加到语言中。
这也是与其他语言的不同之处,例如 C# 将 async 以及 await 作为语法的一部分。而在 Kotlin 中,他们都只是库函数。
Kotlin 编写异步代码: suspend 函数
Kotlin 编写异步代码的方式是使用协程,这是一种计算可被挂起的想法。即一种函数可以在某个时刻暂停执行并稍后恢复的想法。
协程的一个好处是,当涉及到开发人员时,编写非阻塞代码与编写阻塞代码基本相同。编程模型本身并没有真正改变。
以下面的代码为例
代码语言:javascript复制fun postItem(item: Item) {
launch {
val token = preparePost()
val post = submitPost(token, item)
processPost(post)
}
}
suspend fun preparePost(): Token {
// 发起请求并挂起该协程
return suspendCoroutine { /* ... */ }
}
此代码将启动长时间运行的操作,而不会阻塞主线程。preparePost 就是所谓的 可挂起的函数,因此它含有 suspend 前缀。这意味着如上所述,该函数将被执行、暂停执行以及在某个时间点恢复。
该函数的签名保持完全相同。唯一的不同是它被添加了 suspend 修饰符。但是返回类型依然是我们想要的类型。
编写这段代码代码就好像我们正在编写同步代码,自上而下,不需要任何特殊语法,除了使用一个名为 launch 的函数,它实质上启动了该协程(在其他教程中介绍)。
编程模型和 API 保持不变。我们可以继续使用循环,异常处理等,而且不需要学习一整套新的 API。
它与平台无关。无论我们是面向 JVM,JavaScript 还是其他任何平台,我们编写的代码都是相同的。编译器负责将其适应每个平台。
Kotlin 中协程的实现原理
Kotlin 协程本质上是依托线程执行的。具体地说,当一个 Kotlin 协程被创建,底层会创建相应的 Task (Runnable 实例),然后将 Task 添加到任务队列(LockFreeTaskQueue),并发放一个许可证,唤醒一个 Worker。Kotlin 后台维护了共享线程池 CoroutineScheduler,里面有若干个 Worker 守护线程 (Thread 实例),Worker 会从任务队列获取 Task 并执行。
整个流程抽象如下:
https://mp.weixin.qq.com/s/mODioyovzSYs9W_n2imAuQ