并发相关介绍
# 并发与并行介绍
# 并发
- 看起来像同时运行的,就是并发
# 并行
- 真正的同时执行,就是并行
# 注意
- 并行可以称之为并发,但并发不能称之为并行
- 单核计算机无法实现并行,但可以实现并发
# 多道技术
# 作用
- 让单核也能实现并发的效果,节省多个程序运行时的总耗时
# 单道与多道的区别
- 单道(串行)
- 等前面的任务执行完,才会执行后面的任务
任务A(读取到内存,CPU处理)
↓
任务B(读取到内存,CPU处理)
↓
任务C(读取到内存,CPU处理)
1
2
3
4
5
2
3
4
5
- 多道(并行)
- 在CPU处理任务A的时候,控制硬盘提前将任务B读入,然后在CPU处理完任务A后,就可以立马处理任务B,同时控制硬盘读取任务C到内存,后续以此类推
任务A-读到内存 —> 任务A-CPU处理 —> 任务C-读到内存 —> 任务C-CPU处理... ...
任务B-读到内存 —> 任务B-CPU处理 —> 任务D-读到内存... ...
1
2
2
# 多道技术重点
- 空间上的复用
- 多个程序共用一套计算机硬件
- 时间上的复用
- 通过切换和保存状态,提高程序的运行效率
- 多道技术的耗时,一般以耗时最久的任务为准
# 切换
- 切换是为了节省耗时,在某硬件处理完某个任务的某部分后,立即切换来处理其他的任务
- 触发CPU切换的两种情况
- 情况一
- 当一个程序遇到IO操作的时候,操作系统会剥夺该程序的CPU执行权限
- 由于程序IO操作时CPU是不工作的,所以在这种情况下,操作系统会将CPU的执行权限分配给其他需要CPU的程序,而在程序IO操作完后,又会将CPU的执行权限重新分配回去
- 作用是提高CPU的利用率,并且不影响程序的执行效率
- 情况二
- 当一个程序长时间占用CPU的时候,操作系统会剥夺该程序的CPU执行权限,然后与其他程序轮询着共用,会给人一种并发的错觉
- 作用是虽然降低了程序的执行效率 (原本时间+切换时间),但是会给人多个程序同时执行的感觉
- 但切换时间是非常快的,人其实难以感知
- 情况一
# 保存状态
- 保存状态是为了再切换回去时,能够继续上一个任务的运行
# 进程调度
# 先来先服务调度算法
- 对长作业有利,对短作业有弊
- 因为长作业工作时,短作业只能一直等待,直到长作业工作完,现在已经被淘汰
# 短作业优先调度算法
- 对短作业有利,对长作业无益
- 在遇到短作业时,将长作业放到后面再工作,优先处理短作业
# 时间片轮转法 + 多级反馈队列
- 时间片
- 将固定的时间切分成N多份,每一份就表示一个时间片
- 原理
- 在程序运行时,会给每个程序分配一个时间片(比如3秒钟)
- 时间片不同的迭代次数代表着不同的队列
- 如:第一次分配时间片就是第一个队列,第二次分配时间片就是第二个队列,以此类推
- 但如果程序运行了1个时间片还没有结束,就会再给分配程序1个时间片
- 分配的时间片次数越多,说明程序运行的时间越长,任务执行的优先级也就会越低
- 当第一个队列出现了新的任务,由于优先级的关系,CPU就会停止当前正在执行的后面的队列的任务,以优先运行第一个队列的任务
- 在linux中可以给任务设置优先级,但一般不用特意的设置优先级
- 在程序运行时,会给每个程序分配一个时间片(比如3秒钟)
# 进程运行的三状态
# 介绍
- 在程序运行后,程序会进入以下几个状态
# 就绪状态
- 当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态
- 例如:从硬盘读取代码到内存等
# 运行状态
- 当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态
- 例如:
print("running...")
- 例如:
# 阻塞状态
- 正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。
- 引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等
- 例如
sleep(3)
、input()
等
- 例如
# 注意
- 阻塞之后,并不会立刻运行接下来的代码,而是先就绪,等待操作系统调度,然后再运行
# 两对重要概念
# 同步和异步
- 同步和异步,描述的是任务的提交方式
- 同步
- 任务提交之后,一直等待任务的结果返回,等待的过程中不做任何事
- 例如
import time
def func():
time.sleep(3)
print(aaa)
res = func()
print(bbb)
1
2
3
4
5
6
2
3
4
5
6
- 异步
- 任务提交之后,不原地等待任务的结果返回,而是去做其他的事情
- 等到任务完成后,会有一个异步回调机制(回调函数)来对其任务结果进行处理
# 阻塞和非阻塞
- 阻塞和非阻塞,描述的是程序的运行状态
- 阻塞
- 阻塞状态
- 非阻塞
- 就绪状态 和 运行状态
- 我们应该尽量让我们写的代码运行时,只在就绪态和运行态之间切换
# 上述概念的组合
- 最高效的一种组合:异步非阻塞
- 异步非阻塞的框架非常的快