使用 Kotlin 进行 Android 编程
by Pierre-Olivier Laurence, Amanda Hinchman-Dominguez, G. Blake Meike, Mike Dunn
第 7 章 Coroutines 概念
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
在上一章中,我们了解了线程模型的缺陷。作为线程模型的替代方案,Kotlin 语言有一个名为kotlinx.coroutines 的库,旨在解决前面提到的限制问题。启用了例行程序的基元允许开发人员以较低的成本编写顺序异步代码。 例行程序的设计包括暂停函数、结构化并发以及其他特定的考虑因素,如例行程序上下文和例行程序范围。这些主题彼此密切相关。我们将以循序渐进、易于理解的方式逐一介绍这些注意事项。
Coroutine 究竟是什么?
Kotlin 官方文档将 coroutines 定义为 "轻量级线程",目的是利用现有的众所周知的范式。你可以将 coroutines 概念化为可以分派给非阻塞线程的代码块。
coroutines 的确是轻量级的,但需要注意的是,coroutines本身并不是线程。 事实上,许多 coroutines 都可以在单个线程上运行,尽管每个线程都有自己的生命周期。 在本节中,你将看到它们实际上只是状态机,每个状态对应于某个线程最终要执行的代码块。
备注
你可能会惊讶地发现,Coroutines 的概念可以追溯到 20 世纪 60 年代初 Cobol 编译器的诞生,它在汇编语言中使用了暂停和启动函数的思想。 在 Go、Perl 和 Python 等语言中也可以看到 Coroutines 的身影。
coroutine 库提供了一些管理这些线程的工具。不过,如果需要,您也可以配置例程生成器,自行管理线程。
你的第一个 Coroutine
在本节中,我们将介绍kotlinx.coroutines软件包中的大量新词汇和新概念。为了让学习更加顺利,我们选择从一个简单的 coroutine 使用开始,并逐步解释其工作原理。
下面的示例以及本章中的其他示例都使用了kotlinx.coroutines 软件包中声明的语义:
funmain()=runBlocking{valjob:Job=launch{vari=0while(true){println("$iI'm working")i++delay(10)}}delay(30)job.cancel()}
runBlocking 方法运行一个新的例行程序,并阻塞当前线程,直到例行程序工作完成。 该例行程序生成器通常用于主函数和测试,因为它是连接常规阻塞代码的桥梁。
在代码块中,我们使用launch 函数创建了一个例程。因为它创建了一个例程,所以它是一个例程创建器--稍后你将看到其他例程创建器的存在。launch 方法返回对Job 的引用,该引用表示所启动的 coroutine 的生命周期。
在该例行程序中,有一个while-loop,它无限期地执行。在job 例程下面,你可能会注意到job 稍后会被取消。为了演示这意味着什么,我们可以运行我们的程序,输出如下:
0 I'm working 1 I'm working 2 I'm working
看来,例行程序的运行就像上了发条一样。与此同时,代码继续在主线程中执行,在delay 调用给出的 30 毫秒窗口内,我们总共打印了三行,如图 7-1 所示。
图 7-1. 第一个例行程序
delay 函数的用法与Thread.sleep 有几分相似。主要区别在于delay 是非阻塞的,而Thread.sleep(...) ...