区块链技术博客
www.b2bchain.cn

Kotlin实用指南 | 0xb – 协程 (上)求职学习资料

D0b2wT.gif

本文介绍了Kotlin实用指南 | 0xb – 协程 (上)求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

Kotlin 1.1 带来实验特性 协程Coroutines,直到 Kotlin 1.3转正 (语法和标准库API稳定)。

0x1、追根溯源

在具体讲解Kotlin协程前,先来点前置概念相关的名词术语,以尽量简单通俗的方式讲解一波,有助于后续Kotlin协程的学习~

1、同步 & 异步

撇开编程的东西不说,通过 坐公交 的形象例子帮助理解 同步和异步

  • 乘客排队等公交车,车来了,前面扫码上车,一个扫完到下一个扫,一种 `串行化` 的关系,这是`同步`
  • 乘客前门上车,后门下车,互不影响,同时进行,一种 `并行化` 的关系,这是 `异步`

乘客上下车,可以看做两个任务,司机开车也是一个任务,这两者是异步关系,即可以同时进行,乘客还没上完车,司机就把车开走,也是可以的。

Kotlin实用指南 | 0xb - 协程 (上)

不过这样的操作显然时不合常理的,正常来说,司机应该等乘客上下车完毕才发车,那司机怎么知道:

Kotlin实用指南 | 0xb - 协程 (上)

常规操作有两种:

  • 主动(轮询) → 每隔一段时间查看前后门监控,看下有无乘客上下车;
  • 被动(回调) → 早期的公交车都会配有一名乘车员,没乘客上下车,她就会喊司机开车;
Kotlin实用指南 | 0xb - 协程 (上)

不过,任务的进行不一定是顺风顺水的,有可能会出现异常,比如:

乘客前门上车,突然有人晕倒了,上车任务卡住无法继续进行下去,此时处于 同步异常

而乘客上车和司机开车两个任务属于 异步关系,所以这个异常对司机来说是 异步异常

既然是异常,肯定离不开 异常的捕获与处理,处理这里也涉及到了 任务的取消,比如发生上面这样的异常,取消乘客上车任务,司机立马开车送院。


2、堵塞 & 非堵塞

同步与异步的关注点是 是否同时进行,而堵塞与非堵塞关注的是 能否继续进行,还是坐公交的例子:

  • 有乘客上下车,司机发车就需要 `等待`,此时发车的任务就处于 `堵塞` 状态;
  • 乘客上下车完毕,司机又可以发车,此时发车的任务处于 `非堵塞` 状态;

堵塞的真正含义

关心的事物由于某些原因,无法继续进行,因此让你等待。

等待

只是堵塞的一个副作用,表明随时间流逝,没有任何有意义的事物发生或进行。

当然堵塞时也没必要干等着,可以做点其他无关的事物,因为这不影响你对相关事物的等待。

比如司机在等发车时,可以喝喝茶,看看手机等,但不能离开。

而计算机没人那么灵活,堵塞时 干等 最容易实现,只需挂起线程,让出CPU即可,等条件满足时,再重新调度此线程。


3、程序


回到编程相关,任务 对应计算机中的 程序,定义如下:

为了完成特定任务,用某种编程语言编写的一组指令集合(一组静态代码)

CPU处理器会逐条执行指令,哪怕出现外部中断,也只是从当前程序切换到另一个段程序,继续逐条执行。

Kotlin实用指南 | 0xb - 协程 (上)

与预期一致,代码逐条执行,但在有些业务场景 顺序结构 就有些无能为力了,比如:

女朋友:你下班后去超市买10个鸡蛋回来,看到有卖西瓜的就买1个

此时需要用到四种 基础控制流 中的另外一种:选择执行,代码如下:

Kotlin实用指南 | 0xb - 协程 (上)

剩下两种基础控制流为 迭代和递归,我们使用 控制流 来完成 逻辑流,程序执行到哪,逻辑就执行到哪。

这样的程序结构清晰,可读性好,比较符合编程人员的思维习惯,这也是 同步编程 的方式。


4、进程

同一时刻只有一个程序在内存中被CPU调用运行。

假设有A、B两个程序,A正在运行,此时需读取大量输入数据(IO操作),那么CPU只能干等,知道A程序数据读取完毕,再继续往下执行,A执行完后,再去执行程序B,这个等待的过程白白浪费CPU资源。

看着有点蠢?能不能这样:

当程序A读取数据的时,切换到程序B去执行,当A读取完数据,让程序B暂停,切换回程序A执行?

当然可以,不过在计算机中里 切换 这个名词被细分为两种状态:

  • `挂起`:保存程序当前状态,停止当前程序;
  • `激活`:恢复程序状态,继续执行程序;

这里的切换,涉及到了 程序状态的保存和恢复,而程序A和B所需的系统资源(内存、硬盘等)是不一样的,还需要一个东西来记录程序A和B各自需要什么资源,还有系统控制程序AB切换,要一个标志来识别等等,于是乎有了一个 进程的抽象

进程的定义

程序在一个数据集上的一次动态执行过程,一般由下述三个部分组成:

  • `程序`:描述进程要完成的功能及如何完成;
  • `数据集`:程序在执行过程中所需的资源;
  • `进程控制块`:记录进程的外部特征,描述执行变化过程,系统利用它来控制、管理进程、是系统感知进程存在的唯一标志;

进程的出现使得多个程序得以 并发 执行,提高了系统效率及资源利用率,但存在下述问题:

  • ① 单个进程只能干一件事,进程中的代码依旧是串行执行;
  • ② 执行过程如果堵塞,整个进程就会挂起,即使进程中某些工作不依赖于正在等待的资源,也不会执行;
  • ③ 多个进程间的内存无法共享,进程间通讯比较麻烦;

于是乎划分粒度更小的 线程 出现了~


5、线程

线程的出现时为了 降低上下文切换消耗,提高系统的并发性,并突破一个进程只能干一件事的缺陷,是的 进程内并发 成为可能。

线程的定义

轻量级的进程,基本的CPU执行单元,亦是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器组合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。

重要区分

进程资源分配 的最小单位 —— 线程CPU调度 的最小单位

线程与进程的关系

  • ① 一个程序至少有一个进程,一个进程至少有一个线程,可以把进程理解为 `线程的容器`
  • ② 进程在执行过程中拥有 `独立的内存单元`,该进程里的多个线程 `共享内存`;
  • ③ 进程可以扩展到 `多机`,线程最多适合 `多核`
  • ④ 每个独立线程有一个程序运行的入口、顺序执行列和程序出口,但不能独立运行,需依存于应用程序中,由应用程序提供多个线程执行控制;

Tips:进程和线程都是一个时间段的描述,是 CPU工作时间段的描述,只是颗粒大小不同。


6、并发 & 并行

上面提到一个名词 并发(Concurrency),指的是:

同一时刻只有一条指令执行,但多个进程指令被快速地轮换执行,使得在宏观上有同时执行的效果,微观上并不是同时执行,只是把CPU时间分成若干段,使得多个进程快速交替地执行,存在于单核或多核CPU系统中。

而另一个很容易混淆的名词 并行(Parallel) 则是:

同一时刻,有多条指令在多个处理器上同时执行,从微观和宏观上看,都是一起执行的,存在于多核CPU系统中。


7、协作式 & 抢夺式

单核CPU,同一时刻只有一个进程在执行,这么多进程,CPU的时间片该如何分配呢?

协作式多任务

早期的操作系统采用的就是协作时多任务,即:

由进程主动让出执行权,如当前进程需等待IO操作,主动让出CPU,由系统调度下一个进程。

每个进程都循规蹈矩,该让出CPU就让出CPU,是挺和谐的,但也存在一个隐患:

单个进程可以完全霸占CPU

计算机中的进程良莠不齐,先不说那种居心叵测的进程了,如果是健壮性比较差的进程,运行中途发生了死循环、死锁等,会导致整个系统陷入瘫痪!

在这种鱼龙混杂的大环境下,把执行权托付给进程自身,肯定是不符合基础国情,由操作系统扛大旗的 抢占式多任务 横空出世~

抢占式多任务

Kotlin 1.1 带来实验特性 协程Coroutines,直到 Kotlin 1.3转正 (语法和标准库API稳定)。

0x1、追根溯源

在具体讲解Kotlin协程前,先来点前置概念相关的名词术语,以尽量简单通俗的方式讲解一波,有助于后续Kotlin协程的学习~

1、同步 & 异步

撇开编程的东西不说,通过 坐公交 的形象例子帮助理解 同步和异步

  • 乘客排队等公交车,车来了,前面扫码上车,一个扫完到下一个扫,一种 `串行化` 的关系,这是`同步`
  • 乘客前门上车,后门下车,互不影响,同时进行,一种 `并行化` 的关系,这是 `异步`

乘客上下车,可以看做两个任务,司机开车也是一个任务,这两者是异步关系,即可以同时进行,乘客还没上完车,司机就把车开走,也是可以的。

Kotlin实用指南 | 0xb - 协程 (上)

不过这样的操作显然时不合常理的,正常来说,司机应该等乘客上下车完毕才发车,那司机怎么知道:

Kotlin实用指南 | 0xb - 协程 (上)

常规操作有两种:

  • 主动(轮询) → 每隔一段时间查看前后门监控,看下有无乘客上下车;
  • 被动(回调) → 早期的公交车都会配有一名乘车员,没乘客上下车,她就会喊司机开车;
Kotlin实用指南 | 0xb - 协程 (上)

不过,任务的进行不一定是顺风顺水的,有可能会出现异常,比如:

乘客前门上车,突然有人晕倒了,上车任务卡住无法继续进行下去,此时处于 同步异常

而乘客上车和司机开车两个任务属于 异步关系,所以这个异常对司机来说是 异步异常

既然是异常,肯定离不开 异常的捕获与处理,处理这里也涉及到了 任务的取消,比如发生上面这样的异常,取消乘客上车任务,司机立马开车送院。


2、堵塞 & 非堵塞

同步与异步的关注点是 是否同时进行,而堵塞与非堵塞关注的是 能否继续进行,还是坐公交的例子:

  • 有乘客上下车,司机发车就需要 `等待`,此时发车的任务就处于 `堵塞` 状态;
  • 乘客上下车完毕,司机又可以发车,此时发车的任务处于 `非堵塞` 状态;

堵塞的真正含义

关心的事物由于某些原因,无法继续进行,因此让你等待。

等待

只是堵塞的一个副作用,表明随时间流逝,没有任何有意义的事物发生或进行。

当然堵塞时也没必要干等着,可以做点其他无关的事物,因为这不影响你对相关事物的等待。

比如司机在等发车时,可以喝喝茶,看看手机等,但不能离开。

而计算机没人那么灵活,堵塞时 干等 最容易实现,只需挂起线程,让出CPU即可,等条件满足时,再重新调度此线程。


3、程序


回到编程相关,任务 对应计算机中的 程序,定义如下:

为了完成特定任务,用某种编程语言编写的一组指令集合(一组静态代码)

CPU处理器会逐条执行指令,哪怕出现外部中断,也只是从当前程序切换到另一个段程序,继续逐条执行。

Kotlin实用指南 | 0xb - 协程 (上)

与预期一致,代码逐条执行,但在有些业务场景 顺序结构 就有些无能为力了,比如:

女朋友:你下班后去超市买10个鸡蛋回来,看到有卖西瓜的就买1个

此时需要用到四种 基础控制流 中的另外一种:选择执行,代码如下:

Kotlin实用指南 | 0xb - 协程 (上)

剩下两种基础控制流为 迭代和递归,我们使用 控制流 来完成 逻辑流,程序执行到哪,逻辑就执行到哪。

这样的程序结构清晰,可读性好,比较符合编程人员的思维习惯,这也是 同步编程 的方式。


4、进程

同一时刻只有一个程序在内存中被CPU调用运行。

假设有A、B两个程序,A正在运行,此时需读取大量输入数据(IO操作),那么CPU只能干等,知道A程序数据读取完毕,再继续往下执行,A执行完后,再去执行程序B,这个等待的过程白白浪费CPU资源。

看着有点蠢?能不能这样:

当程序A读取数据的时,切换到程序B去执行,当A读取完数据,让程序B暂停,切换回程序A执行?

当然可以,不过在计算机中里 切换 这个名词被细分为两种状态:

  • `挂起`:保存程序当前状态,停止当前程序;
  • `激活`:恢复程序状态,继续执行程序;

这里的切换,涉及到了 程序状态的保存和恢复,而程序A和B所需的系统资源(内存、硬盘等)是不一样的,还需要一个东西来记录程序A和B各自需要什么资源,还有系统控制程序AB切换,要一个标志来识别等等,于是乎有了一个 进程的抽象

进程的定义

程序在一个数据集上的一次动态执行过程,一般由下述三个部分组成:

  • `程序`:描述进程要完成的功能及如何完成;
  • `数据集`:程序在执行过程中所需的资源;
  • `进程控制块`:记录进程的外部特征,描述执行变化过程,系统利用它来控制、管理进程、是系统感知进程存在的唯一标志;

进程的出现使得多个程序得以 并发 执行,提高了系统效率及资源利用率,但存在下述问题:

  • ① 单个进程只能干一件事,进程中的代码依旧是串行执行;
  • ② 执行过程如果堵塞,整个进程就会挂起,即使进程中某些工作不依赖于正在等待的资源,也不会执行;
  • ③ 多个进程间的内存无法共享,进程间通讯比较麻烦;

于是乎划分粒度更小的 线程 出现了~


5、线程

线程的出现时为了 降低上下文切换消耗,提高系统的并发性,并突破一个进程只能干一件事的缺陷,是的 进程内并发 成为可能。

线程的定义

轻量级的进程,基本的CPU执行单元,亦是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器组合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。

重要区分

进程资源分配 的最小单位 —— 线程CPU调度 的最小单位

线程与进程的关系

  • ① 一个程序至少有一个进程,一个进程至少有一个线程,可以把进程理解为 `线程的容器`
  • ② 进程在执行过程中拥有 `独立的内存单元`,该进程里的多个线程 `共享内存`;
  • ③ 进程可以扩展到 `多机`,线程最多适合 `多核`
  • ④ 每个独立线程有一个程序运行的入口、顺序执行列和程序出口,但不能独立运行,需依存于应用程序中,由应用程序提供多个线程执行控制;

Tips:进程和线程都是一个时间段的描述,是 CPU工作时间段的描述,只是颗粒大小不同。


6、并发 & 并行

上面提到一个名词 并发(Concurrency),指的是:

同一时刻只有一条指令执行,但多个进程指令被快速地轮换执行,使得在宏观上有同时执行的效果,微观上并不是同时执行,只是把CPU时间分成若干段,使得多个进程快速交替地执行,存在于单核或多核CPU系统中。

而另一个很容易混淆的名词 并行(Parallel) 则是:

同一时刻,有多条指令在多个处理器上同时执行,从微观和宏观上看,都是一起执行的,存在于多核CPU系统中。


7、协作式 & 抢夺式

单核CPU,同一时刻只有一个进程在执行,这么多进程,CPU的时间片该如何分配呢?

协作式多任务

早期的操作系统采用的就是协作时多任务,即:

由进程主动让出执行权,如当前进程需等待IO操作,主动让出CPU,由系统调度下一个进程。

每个进程都循规蹈矩,该让出CPU就让出CPU,是挺和谐的,但也存在一个隐患:

单个进程可以完全霸占CPU

计算机中的进程良莠不齐,先不说那种居心叵测的进程了,如果是健壮性比较差的进程,运行中途发生了死循环、死锁等,会导致整个系统陷入瘫痪!

在这种鱼龙混杂的大环境下,把执行权托付给进程自身,肯定是不符合基础国情,由操作系统扛大旗的 抢占式多任务 横空出世~

抢占式多任务

Kotlin 1.1 带来实验特性 协程Coroutines,直到 Kotlin 1.3转正 (语法和标准库API稳定)。

0x1、追根溯源

在具体讲解Kotlin协程前,先来点前置概念相关的名词术语,以尽量简单通俗的方式讲解一波,有助于后续Kotlin协程的学习~

1、同步 & 异步

撇开编程的东西不说,通过 坐公交 的形象例子帮助理解 同步和异步

  • 乘客排队等公交车,车来了,前面扫码上车,一个扫完到下一个扫,一种 `串行化` 的关系,这是`同步`
  • 乘客前门上车,后门下车,互不影响,同时进行,一种 `并行化` 的关系,这是 `异步`

乘客上下车,可以看做两个任务,司机开车也是一个任务,这两者是异步关系,即可以同时进行,乘客还没上完车,司机就把车开走,也是可以的。

Kotlin实用指南 | 0xb - 协程 (上)

不过这样的操作显然时不合常理的,正常来说,司机应该等乘客上下车完毕才发车,那司机怎么知道:

Kotlin实用指南 | 0xb - 协程 (上)

常规操作有两种:

  • 主动(轮询) → 每隔一段时间查看前后门监控,看下有无乘客上下车;
  • 被动(回调) → 早期的公交车都会配有一名乘车员,没乘客上下车,她就会喊司机开车;
Kotlin实用指南 | 0xb - 协程 (上)

不过,任务的进行不一定是顺风顺水的,有可能会出现异常,比如:

乘客前门上车,突然有人晕倒了,上车任务卡住无法继续进行下去,此时处于 同步异常

而乘客上车和司机开车两个任务属于 异步关系,所以这个异常对司机来说是 异步异常

既然是异常,肯定离不开 异常的捕获与处理,处理这里也涉及到了 任务的取消,比如发生上面这样的异常,取消乘客上车任务,司机立马开车送院。


2、堵塞 & 非堵塞

同步与异步的关注点是 是否同时进行,而堵塞与非堵塞关注的是 能否继续进行,还是坐公交的例子:

  • 有乘客上下车,司机发车就需要 `等待`,此时发车的任务就处于 `堵塞` 状态;
  • 乘客上下车完毕,司机又可以发车,此时发车的任务处于 `非堵塞` 状态;

堵塞的真正含义

关心的事物由于某些原因,无法继续进行,因此让你等待。

等待

只是堵塞的一个副作用,表明随时间流逝,没有任何有意义的事物发生或进行。

当然堵塞时也没必要干等着,可以做点其他无关的事物,因为这不影响你对相关事物的等待。

比如司机在等发车时,可以喝喝茶,看看手机等,但不能离开。

而计算机没人那么灵活,堵塞时 干等 最容易实现,只需挂起线程,让出CPU即可,等条件满足时,再重新调度此线程。


3、程序


回到编程相关,任务 对应计算机中的 程序,定义如下:

为了完成特定任务,用某种编程语言编写的一组指令集合(一组静态代码)

CPU处理器会逐条执行指令,哪怕出现外部中断,也只是从当前程序切换到另一个段程序,继续逐条执行。

Kotlin实用指南 | 0xb - 协程 (上)

与预期一致,代码逐条执行,但在有些业务场景 顺序结构 就有些无能为力了,比如:

女朋友:你下班后去超市买10个鸡蛋回来,看到有卖西瓜的就买1个

此时需要用到四种 基础控制流 中的另外一种:选择执行,代码如下:

Kotlin实用指南 | 0xb - 协程 (上)

剩下两种基础控制流为 迭代和递归,我们使用 控制流 来完成 逻辑流,程序执行到哪,逻辑就执行到哪。

这样的程序结构清晰,可读性好,比较符合编程人员的思维习惯,这也是 同步编程 的方式。


4、进程

同一时刻只有一个程序在内存中被CPU调用运行。

假设有A、B两个程序,A正在运行,此时需读取大量输入数据(IO操作),那么CPU只能干等,知道A程序数据读取完毕,再继续往下执行,A执行完后,再去执行程序B,这个等待的过程白白浪费CPU资源。

看着有点蠢?能不能这样:

当程序A读取数据的时,切换到程序B去执行,当A读取完数据,让程序B暂停,切换回程序A执行?

当然可以,不过在计算机中里 切换 这个名词被细分为两种状态:

  • `挂起`:保存程序当前状态,停止当前程序;
  • `激活`:恢复程序状态,继续执行程序;

这里的切换,涉及到了 程序状态的保存和恢复,而程序A和B所需的系统资源(内存、硬盘等)是不一样的,还需要一个东西来记录程序A和B各自需要什么资源,还有系统控制程序AB切换,要一个标志来识别等等,于是乎有了一个 进程的抽象

进程的定义

程序在一个数据集上的一次动态执行过程,一般由下述三个部分组成:

  • `程序`:描述进程要完成的功能及如何完成;
  • `数据集`:程序在执行过程中所需的资源;
  • `进程控制块`:记录进程的外部特征,描述执行变化过程,系统利用它来控制、管理进程、是系统感知进程存在的唯一标志;

进程的出现使得多个程序得以 并发 执行,提高了系统效率及资源利用率,但存在下述问题:

  • ① 单个进程只能干一件事,进程中的代码依旧是串行执行;
  • ② 执行过程如果堵塞,整个进程就会挂起,即使进程中某些工作不依赖于正在等待的资源,也不会执行;
  • ③ 多个进程间的内存无法共享,进程间通讯比较麻烦;

于是乎划分粒度更小的 线程 出现了~


5、线程

线程的出现时为了 降低上下文切换消耗,提高系统的并发性,并突破一个进程只能干一件事的缺陷,是的 进程内并发 成为可能。

线程的定义

轻量级的进程,基本的CPU执行单元,亦是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器组合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。

重要区分

进程资源分配 的最小单位 —— 线程CPU调度 的最小单位

线程与进程的关系

  • ① 一个程序至少有一个进程,一个进程至少有一个线程,可以把进程理解为 `线程的容器`
  • ② 进程在执行过程中拥有 `独立的内存单元`,该进程里的多个线程 `共享内存`;
  • ③ 进程可以扩展到 `多机`,线程最多适合 `多核`
  • ④ 每个独立线程有一个程序运行的入口、顺序执行列和程序出口,但不能独立运行,需依存于应用程序中,由应用程序提供多个线程执行控制;

Tips:进程和线程都是一个时间段的描述,是 CPU工作时间段的描述,只是颗粒大小不同。


6、并发 & 并行

上面提到一个名词 并发(Concurrency),指的是:

同一时刻只有一条指令执行,但多个进程指令被快速地轮换执行,使得在宏观上有同时执行的效果,微观上并不是同时执行,只是把CPU时间分成若干段,使得多个进程快速交替地执行,存在于单核或多核CPU系统中。

而另一个很容易混淆的名词 并行(Parallel) 则是:

同一时刻,有多条指令在多个处理器上同时执行,从微观和宏观上看,都是一起执行的,存在于多核CPU系统中。


7、协作式 & 抢夺式

单核CPU,同一时刻只有一个进程在执行,这么多进程,CPU的时间片该如何分配呢?

协作式多任务

早期的操作系统采用的就是协作时多任务,即:

由进程主动让出执行权,如当前进程需等待IO操作,主动让出CPU,由系统调度下一个进程。

每个进程都循规蹈矩,该让出CPU就让出CPU,是挺和谐的,但也存在一个隐患:

单个进程可以完全霸占CPU

计算机中的进程良莠不齐,先不说那种居心叵测的进程了,如果是健壮性比较差的进程,运行中途发生了死循环、死锁等,会导致整个系统陷入瘫痪!

在这种鱼龙混杂的大环境下,把执行权托付给进程自身,肯定是不符合基础国情,由操作系统扛大旗的 抢占式多任务 横空出世~

抢占式多任务

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » Kotlin实用指南 | 0xb – 协程 (上)求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们