0.前言
最近在复习Golang语言,又遇到了“协程”这个大兄弟。干脆花了一天时间把进程,线程与协程进行了一个对比分析,并对应做了一些图。
相关背景概念
- 并发:并发是指一个时间段内,有多个程序同时运行,但是任意时刻只有一个程序在CPU上运行。
- 并行:指任意时刻点上,有多个程序同时运行在多个CPU上
- 同步:指代码调用IO操作时,必须等待IO操作完成才返回的调用方式
- 异步:指代码调用IO操作时,不必要等IO操作完成就返回的调用方式
- 阻塞:指调用函数时候当前线程被挂起
- 非阻塞:指调用函数时候当前线程不会被挂起,而是立即返回
区别
直接上图,三者在运行时的区别
区别
进程 | 线程 | 协程 | |
---|---|---|---|
概念 | - 一段程序的执行过程 - 是资源分配的最小单位 | 操作系统(内核)运算调度的最小单位 | 用户态实现的运算调度单位 可暂停和恢复执行的过程(函数) |
独立资源 | - 虚拟内存空间(代码段、数据段、堆栈等) - 内核栈、thread_info、task_struct(pid,tgid等) - 寄存器组的值 | - 线程id(pid) - 堆栈 - 寄存器组的值 | - 栈 - 部分栈切换的寄存器 |
切换代价 | 高 | 中 | 低 |
通信(同步)方式 | 1. 管道/匿名管道 2. 有名管道 3. 信号 4. 消息队列 5. 共享内存 6. 信号量 7. 套接字 | 1. 锁机制 2. 信号量机制 3.信号机制 | Future,channel, pub/sub等 |
优点 | 1. 进程间相互独立,一个进程出了问题不会影响其它进程 2. 可以利用多CPU的资源 | 1. 线程之间共享内存和变量,通信比较方便 2. 程序逻辑和控制方式简单 3. 上下文切换资源消耗中等 | 1. 无须原子操作锁定及同步的开销 2. 上下文切换资源小 3. 高并发性、高扩展性、低成本 |
缺点 | 1. 需要跨进程边界,当数据交流大是开销比较高 2. 创建、上下文切换开销大 | 1.线程之间的同步和加锁控制比较麻烦 2. 一个线程的崩溃可能影响到整个程序的稳定性 | 1. 不能使用多核资源 |
适用场景 | CPU密集型操作(如科学计算) | 1. 多核CPU 2. I/O密集操作(网络I/O,磁盘I/O) | 单核CPU I/O密集型操作(网络I/O,如秒杀系统,RPC服务器,即时通讯等) |
1.1 为什么会有进程?
- CPU运行太快,而RAM和其它设备太慢
- 为了榨取CPU的计算资源便出现了进程,用于轮流分配多任务的计算资源
- 进程就是上下文切换之间程序执行的部分
1.2 为什么会有线程?
- 进程的创建、管理、上下文切换开销太大
- 进程间通信开销太大
1.3 为什么会有协程?
- 线程难以满足异步并发任务需求
- 代码设计,异步让代码逻辑支离破碎
2.1 进程与线程的区别与联系?
这里引用知乎高赞biaodianfu老哥的回答。
进程是火车,线程是火车车厢。
- 概念包含:
- 线程是在进程下运行的(没有火车,车厢无法运行)
- 一个进程可以包含多个线程 (一个火车可以有多个车厢)
- 数据共享:
- 进程间难以数据共享(一个火车上的乘客难以转换到另一个乘客)
- 同一进程下的线程数据容易共享 (一个火车上人员可以走动)
- 计算资源
- 进程消耗的资源多于线程 (多个火车比多个车厢耗费资源)
- 相互间影响
- 一个进程挂了不会影响其它进程 (一个火车坏了另一个火车不会坏)
- 一个线程挂了会影响其它线程 (一个车厢坏了整个火车就难以运行)
- 锁与信号量
- 线程之间资源竞争需要上锁 (火车车厢洗手间的锁)
- 线程之间资源竞争需要限定使用量 (火车餐车的限员)
2.2 线程与协程的区别与联系?
- 联系
- 协程可以看成是用户态的轻量级线程, (绿色线程)
- 一个线程可以包含多个协程
- 区别
- 线程是同步的,强调并行,协程是异步的,强调并发
- 线程是抢占式的,协程是非抢占式的(自己主动退出)
- 协程能保留上一次调用时的状态