「协程」和「Kotlin 协程」

Tips 0:写完全文回头看,我觉得只看总结也够了。可以快进。

前言

最初接触 Kotlin 的时候,Kotlin 协程还处于实验阶段,我也是第一次听说协程的概念。几年过去了,随着 Kotlin 的推广和 Kotlin 协程的发展,我终于在去年年底正式入坑了。

大约5个月的时间,从 demo 用到真实项目,我对 Kotlin 协程的看法也一波三折,从不明觉厉到不过如此,又逐渐变成这东西真不错。

关于 Kotlin 协程我有很多想写的内容,草稿箱和笔记里都有不同的提纲,但第一篇就还是从困扰了我最久的点开始讲起吧,那就是「协程」的概念和 Kotlin 中的协程。

本文中协程和 Kotlin 协程是两种并列的不同的概念,二者没有包含关系。

从协程的概念开始

Tips 1:对于还未接触过协程的人来说,我觉得学习 Kotlin 协程完全不需要去深入理解协程本身的概念,因为 Kotlin 协程并不是真正的协程,早期过度研究概念和对比区别是学习 Kotlin 协程的一条弯路。

根据维基百科的介绍,协程并不是新技术,这个概念正式发布于1963年,是一种实现多任务并发的技术思路,大概与「线程」位于同一级别,二者的区别则是线程采取「抢占式」策略,而协程采取「协作式」策略。

单从概念上看,协程可控性比线程高,似乎是更优解,但协作式的方案不能实现真正的并行,很显然,线程取得了胜利。

「协程」一度沉寂,但随着软件开发的复杂度提升,很多语言都重新捡起了协程的概念来处理异步操作,但具体实现上已经与曾经的协程相去甚远。

Kotlin 协程的目标

Kotlin 协程是一个 JetBrains 官方出品的库,但不包含在 Kotlin 语言标准库中,目标是解决开发者用不好线程的问题(我编的)。

根据官方介绍,Kotlin 协程是用来实现异步任务和非阻塞编程的。以 Android 开发为例,为了保证良好的用户体验,系统规定 UI 线程不可阻塞,以便立刻响应用户输入,所有耗时操作都应该在其他线程实现,再通知 UI 线程更新页面。不只是 Android,所有对外提供服务的程序都有这样的需求,给了 Kotlin 协程更广泛的发挥空间。

Kotlin 协程的功能

Kotlin 的协程使用了协程的概念,通过「挂起」和「恢复」简化了多任务协作的实现代码。Kotlin 协程是一种对同步编程和异步编程统一的抽象封装。

  • 挂起和恢复

挂起和恢复来自协程的基本概念,每个协程自身决定何时挂起何时继续,达成多任务之间协作。

image.png

在一次次调用 suspend 函数的过程中,表面上连续的调用栈实际上已经完成了线程切换。

被挂起和恢复的对象是协程,也就是说在第一次 suspend 之后线程 A 并未被阻塞,还可以执行其他发生在线程 A 的代码。

  • 多任务

任务是一种抽象概念,可以理解成一段代码或者一个函数,执行任务需要一定的时间,任务可能正常完成获得需要的结果,也可能遇到异常而失败。Kotlin 协程的协作是多任务之间的协作,任务通常在不同的线程,但也可以在相同的线程。(一个挂起函数内也可以调用普通函数)

  • 关于简化

只看官方对 Kotlin 协程的介绍可能觉得简化的作用很大,其实那些例子都没有处理 Exception,实际应用协程的时候并不会那么简单。但简化代码并不是虚假宣传,实际上简化的是恢复的过程,协程恢复的过程是将其他任务的处理结果传回来的地方,如果使用回调的话,免不了加一层嵌套,任务越多越复杂。Kotlin 协程的简化是把这些嵌套拉平了。

一段总结

写完之后我又反复读了文章内容,不断修改,但还是觉得漏洞百出。讲述概念的每一处用词都经过了反复推敲,但还是会发现前后矛盾、内容重复、歧义等问题。有点只可意会不可言传的意思了。

总结一下观点吧:

  1. 当对比协程和线程时,通常是指概念上的协程,与 Kotlin 协程不是同一个东西
  2. Kotlin 协程是一个用协程概念在线程框架上封装的库
  3. Kotlin 协程可以解决异步代码难写难读的问题,但并非不可替代的黑科技

投降了,讲概念太可怕了,下一篇写 Kotlin 协程和 ViewModel、Retrofit、Room 的实践。


参考资料:

  1. 协程-维基百科
  2. Coroutine|Kotlin
  3. 《深入理解 Kotlin 协程》

Tips 2: 《深入理解 Kotlin 协程》这本书通过横向对比不同语言的协程实现,或者不同异步任务实现方案阐述了 Kotlin 协程的各方面特点,也有对源码的一些讲解,重理论轻实践,最好在有一定的实践经验之后再看。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享