1. 进程
- 系统资源分配和调度的最小单位,每个进程都有自己的独立内存空间,系统由一个个进程(程序)组成,进程主要包括:
- 文本区域(text region):存储处理器执行的代码
- 数据区域(data region):存储变量和进程执行期间使用的动态分配的内存
- 堆栈(stack region):存储活动过程调用的指令和本地变量
- 进程的创建和销毁都是相对于系统资源,所以是一种比较昂贵的操作,进程主要包括三种状态:
- 等待态:等待某个事件的完成
- 就绪态:等待系统分配处理器以便运行
- 运行态:占有处理器正在运行
- 进程是抢占式地争夺cpu运行自身,cpu单核情况下同一时间只能运行一个进程,单核下多进程则是通过cpu飞快地切换不同进程实现,使得系统看上去像是有多个进程在同时运行。
- 通信问题:
- 由于进程间是隔离的,各自拥有自己的内存资源,因此相对于线程比较安全,所以不同进程之间的数据只能通过IPC(Inter-Process Communication)进行通信共享。
2. 线程
- 线程属于进程(线程是进程的一个实体),是cpu调度和分配的最小单位,线程共享进程的内存地址空间,所以线程几乎不占有系统资源(只拥有一点在运行中必不可少的资源,如程序计数器,一组寄存器和栈)。
- 线程是不安全的,当一个线程崩溃了,会导致整个进程也崩溃,即其它线程也挂了。
- 默认进程内只有一个线程,所以多核cpu处理多进程就像是一个进程一个核心。
- 通信问题:
- 进程相当于一个容器,而线程是运行在容器里面的,因此对于容器内的东西,线程是共享的。线程间的通信可以直接通过全局变量(共享内存)进行通信,但是由此带来的例如多个线程读写同一个地址变量的时候则将带来不可预期的后果,因此这时候引入了各种锁的作用,例如互斥锁等。
- 进程和线程的上下文切换:
- 进程切换分为3步:
- 切换页目录以使用新的地址空间
- 切换内核栈
- 切换硬件上下文
- 线程切换只需要第2、3步,因此进程切换的代价(栈、寄存器、虚拟内存、文件句柄等)会比较大。
- 进程切换分为3步:
3. 协程
- 协程是属于线程的,协程是一种用户态的轻量级线程,协程程序在线程里跑,因此协程又称微线程或纤程。
- 协程没有线程的上下文切换消耗,协程的调度切换是开发者手动切换的,因此更加灵活,所以又叫用户空间线程。
- 协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
- 原子操作性:由于协程是用户调度的,所以不会出现执行一半的代码片段被强制中断,因此无需原子操作锁。
- 协程的实现:
- 迭代器:实现了迭代接口的类,接口函数例如:current,key,next,rewind,valid。迭代器最基本的规定了对象可以通过next返回下一个值,而不是像数组,列表一样一次性返回
- 生成器:使用
yield
关键字的函数,可以多次返回值,生成器实际上也算是实现了迭代器接口(协议)。即生成器也可通过next返回下一个值。
4. 区别
- 进程 & 线程
- 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间;
- 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源;
- 线程是处理器调度的基本单位,但进程不是;
- 二者均可并发执行;
- 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制;
- 协程 & 线程
- 一个线程可以多个协程,一个进程也可以单独拥有多个协程;
- 线程进程都是同步机制,而协程则是异步;
- 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态;