1 串行,并发和并行
首先搞清楚并发和并行的概念
1.1 串行
- 多个任务,执行时一个执行完再执行另一个。
- 比喻:吃完饭再看球赛。
1.2 并发
- 多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,看起来像同时运行,实际上是线程不停切换。
- 比喻: 一会跑去食厅吃饭,一会跑去客厅看球赛。
1.3 并行
- 每个线程分配给独立的核心,线程同时运行。
- 比喻:一边吃饭一边看球赛。
2 进程
- 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。进程=程序+执行。首先程序只有从磁盘加载到内存中cpu才能去运算和处理。处于内存中的程序正在或者将要被CPU执行,这个状态的程序称为进程。
- 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。即除了程序本身还包含所有为该程序运行而分配的资源,比如内存。
2.1 进程引入的背景
- 单道批处理系统(串行)
最开始的操作系统是单道处理系统(一个程序处理完,才能处理下一个程序)
缺点:(1)响应时间慢(客户体验差),(2)cpu利用率非常低
例如:假设一个进程,20%的时间在做cpu运算,80%的时间在做IO等待(发送IO事件时,cpu时闲置的),cpu利用率仅仅只有20%
单道编程模型:cup利用率=1-0.8=20%
- 多道批处理系统(并发)
多道处理系统就是计算机内存中可以同时存放多道(两个以上相互独立的)程序。
执行两个进程的话:1-0.8*0.8=36% (注:去掉进程同时发生io而CPU空闲的概率)
执行三个进程的话:1-0.8*0.8*0.8=48.8%
总结:引入进程模型,目的就是为了满足多道处理系统,而多道处理系统的目的就是为了提高cpu的利用率。随着进程数量的增加,cpu的利用率逐步提高。由于进程多了之后进程之间的切换也会耗费资源,最终CPU利用率趋于平缓。
2.2 多维度理解进程
2.3 进程的产生和消亡
2.4 进程状态
3 线程
3.1 进程引入的背景
举例1:假如内存中现有两个进程,一个是Word文档编辑,一个是视屏播放。假如现在的时间片归属Word文档,用户正在编辑文档并且点击了保存,此时Word进程发生了IO,虽然CPU可以将时间片动态的划分给视频播放器使得CPU没有空闲,但是用户却一直在等待不让打字,等待刚编辑的内容落地的磁盘中之后才能有其他操作,会及其影响效率。如何能够让同一个进程中的写入和编辑并发呢?线程就应运而生,线程将进程切分的更细,比如将Word的IO划分为一个线程,将Word编辑划分成另一个线程。CPU在两个线程间不停的调度,不停的给两个线程分配时间片,从宏观上看Word既可以进行写入操作又可以进行编辑。
举例2:比如360卫士,有很多模块,在电脑体检的时候同时可以进行木马查杀,电脑体检和木马查杀就是线程,360卫士就是进程。
- 一个进程必须有一个线程,也可以有多个线程。
- 线程,有时被称为轻量进程(Lightweight Process,LWP)
3.2 线程切换
- cpu给线程分配时间片(也就是分配给线程的时间),执行完时间片后会切换都另一个线程。
- 切换之前会保存线程的状态,下次时间片再给这个线程时才能知道当前状态。
- 从保存线程A的状态再到切换到线程B时,重新加载线程B的状态的这个过程就叫上下文切换。
- 而上下文切换时会消耗大量的cpu时间。
3.3 线程开销
- 上下文切换消耗
- 线程创建和消亡的开销
- 线程需要保存维持线程本地栈,会消耗内存
4 进程与线程
- 进程是操作系统进行资源(包括cpu、内存、磁盘IO等)分配的最小单位
- 线程是cpu调度和分配的基本单位
- 我们打开的微信,浏览器都是一个进程
- 进程可能有多个子任务,比如微信要接受消息,发送消息,这些子任务就是线程。
- 资源分配给进程,线程共享进程资源。
对比 | 进程 | 线程 |
---|---|---|
定义 | 进程是程序运行的一个实体的运行过程,是系统进行资源分配和调配的一个独立单位 | 线程是进程运行和执行的最小调度单位 |
系统开销 | 创建撤销切换开销大,资源要重新分配和收回 | 仅保存少量寄存器的内容,开销小,在进程的地址空间执行代码 |
拥有资产 | 资源拥有的基本单位 | 基本上不占资源,仅有不可少的资源(程序计数器,一组寄存器和栈) |
调度 | 资源分配的基本单位 | 独立调度分配的单位 |
安全性 | 进程间相互独立,互不影响 | 线程共享一个进程下面的资源,可以互相通信和影响 |
地址空间 | 系统赋予的独立的内存地址空间 | 由相关堆栈寄存器和和线程控制表TCB组成,寄存器可被用来存储线程内的局部变量 |
前面4节讲的都是基于单核CPU,无论进程还是线程,宏观上都是并行,微观上都是串行。
5 CPU与核心
随着科技发展,由单核CPU变成多核CPU。注意多核CPU不是多个CPU,每一个核可以单独处理一个线程,每个核是一个单独的处理单元。多核的出现就是为了能够实现并行。
5.1 物理核
- 物理核数量=cpu数(机子上装的cpu的数量)*每个cpu的核心数
5.2 虚拟核
- 所谓的4核8线程,4核指的是物理核心。通过超线程技术,用一个物理核模拟两个虚拟核,每个核两个线程,总数为8线程。
- 在操作系统看来是8个核,但是实际上是4个物理核。
- 通过超线程技术可以实现单个物理核实现线程级别的并行计算,但是比不上性能两个物理核。
5.3 单核CPU与多核CPU
- 都是一个cpu,不同的是每个cpu上的核心数
- 多核cpu是多个单核cpu的替代方案,多核cpu减小了体积,同时也减少了功耗
- 一个核心只能同时执行一个线程
注意1:多核多线程一定是并发但不一定都是并行。
解析:无论是单核还是多核都会有时间片调度,所以一定是并发的。
假如程序有4个线程,而且有一个4核的CPU,理论上如果每个CPU执行一个线程那么4个线程就变成是并行的了。
可实际情况是根据线程间是否有上下关系来决定,例如线程1执行代码:a = 1 + 1 线程2执行代码 b = a + 1,那么线程2必须得等到线程1执行完了之后才能执行。
- 如果两个线程不相关,对于多核而言两个线程就可以并行。
注意2:多核绑定
在没有绑定核的情况下,同一个线程可能会被不同的核调度执行。在某些特殊场景,多程之间的切换和调度会影响性能和效率,那么怎样才能提高效率和性能呢?
多核绑定可以轻易的解决这个问题,将程绑定到固定的CPU上减少多程之间的调度和切换。
6 多核下线程数量选择
6.1 计算密集型
- 程序主要为复杂的逻辑判断和复杂的运算。
- cpu的利用率高,不用开太多的线程,开太多线程反而会因为线程切换时切换上下文而浪费资源。
6.2 IO密集型
- 程序主要为IO操作,比如磁盘IO(读取文件)和网络IO(网络请求)。(参考3.1中Word文档举例)
- 因为IO操作会阻塞线程,cpu利用率不高,可以开多点线程,阻塞时可以切换到其他就绪线程,提高cpu利用率。