目标:
整理多进程/多线程知识,主要包含如下内容:
1、多进程及其通信方式
2、多线程及其通信方式
3、线程池与进程池
4、调度算法
5、死锁
6、内存管理
第一部分 多进程及其通信方式
1 进程是什么?线程是什么?进程与线程有什么区别?
1)进程是已运行程序的实体,由程序,数据,进程控制块组成。
2)线程是轻量级进程,是处理器的分配单元。
3)主要在调度,开销,地址空间上有区别。
调度:进程是资源分配的单位,线程是调度的单位。
开销: 进程创建和销毁的开销大于线程的开销。
因为进程切换涉及CPU环境保存和设置,线程切换只需保存少量寄存器内容
地址空间: 进程地址空间相互独立,同一进程的各线程共享进程的资源。
2 进程有哪些状态?状态如何切换?
1)运行,就绪,阻塞状态。
运行状态: 进程在处理器上运行。
就绪状态: 获得除处理器外所有所需资源
阻塞状态: 等待某时间二暂停,例如等待输入/输出
2)
运行->阻塞:等待某个事件发生
阻塞->就绪:等待的事件发生
就绪->运行:调度
运行->就绪:时间片到。
3 什么是临界资源?什么是临界区?
1)一次仅允许一个进程使用的资源,例如打印机。
2)临界区是访问临界资源的那段代码。
4 进程间通信有哪些方式?
进程间通信的方式有:管道,信号,消息队列,共享内存,套接字。
管道: 可用于亲缘关系的进程通信。有名管道可以用于无亲缘关系的进程通信。
信号: 通知接收进程有某种事件发生,
消息队列: 一个进程可以向其中写入消息,零一个进程可以从队列中读取消息。
共享内存: 多个进程可以访问同一块内存空间。
在内存划出区域作为共享区,把区域映射到参与通信的各个进程空间。
套接字:即socket,用于不同机器之间的进程通信。
第二部分 多线程及其通信方式
1 线程间通信凡是有哪些?
互斥体(互斥量),信号量,条件变量。
2 临界区与互斥体的区别是什么?
1)临界区只能用来同步本进程的多个线程;
互斥体可以被用于跨进程同步数据。
2)临界区是非内核对象,速度快,互斥体是内核对象,速度慢。
3 多进程和多线程切换时是用户态还是内核态?
1)多进程和多线程切换是进入内核态,而go中自己的goroutine调度是用户态。
4 什么是用户态与内核态?用户态与内核态是如何切换的?为什么要有用户态与内核态?
1)内核态控制计算机硬件资源例如cpu,内存,I/O资源,提供上层应用运行环境,运行在高级别特权。
用户态是上层应用程序的活动空间,运行在低特权级别,必须通过系统调用等来获取内核空间资源。
2)用户态切换到内核态,主要是通过:
系统调用,异常,外围设备中断。
系统调用是申请使用操作系统提供的服务;
异常触发进入到处理异常的内核中;
外围设备中断是完成用户请求向cpu发出中断信号,暂停执行下一条指令而去
执行中断对应的处理程序。
3)限制不同程序访问能力。
第三部分 线程池与进程池
1 线程池的默认queue实现是什么?
python中: 线程池的默认queue实现是用的FIFO队列。
2 线程池有哪些参数?分别有什么用?如果任务数超过的核心线程数,会发生什么?阻塞队列大小是多少?
1)python中有workers,用于设置线程池的大小。
2)任务数超过核心线程数,已提交的任务在队列中,等待其他线程完成后继续处理。
3)阻塞队列大小在python中是通过用户设定的线程池大小决定的,如果用户没有设置,
那么这个值等于系统的cpu个数。
3 线程池原理
主线程是通过队列将任务传递给多个子线程。一旦主线程将任务塞进任务队列,子线程们就会开始争抢,最终只有一个线程能抢到这个任务,并立即进行执行,执行完后将结果放进Future对象就完成了这个任务的完整执行过程。
主线程将任务塞进线程池后得到了这个Future对象,它内部的_result还是空的。如果主线程调用result()方法获取结果,就会阻塞在条件变量上。如果子线程计算任务完成了就会立即调用set_result()方法将结果填充进future对象,并唤醒阻塞在条件变量上的线程,也就是主线程。这时主线程立即醒过来并正常返回结果。
4 进程池原理
主线程将任务塞进TaskQueue(普通内存队列),拿到Future对象
唯一的管理线程从TaskQueue获取任务,塞进CallQueue(分布式跨进程队列)
子进程从CallQueue中争抢任务进行处理
子进程将处理结果塞进ResultQueue(分布式跨进程队列)
管理线程从ResultQueue中获取结果,塞进Future对象
主线程从Future对象中拿到结果
5 跨进程队列
进程池模型中的跨进程队列是用multiprocessing.Queue实现的。
它使用无名套接字sockerpair来完成的跨进程通信,socketpair和socket的区别就在于socketpair不需要端口,不需要走网络协议栈,通过内核的套接字读写缓冲区直接进行跨进程通信。
6 I/O密集型与CPU密集型任务的选择
concurrent提供了两种并发模型,一个是多线程ThreadPoolExecutor,一个是多进程ProcessPoolExecutor。对于IO密集型任务宜使用多线程模型。对于计算密集型任务应该使用多进程模型。
是因为Python GIL的存在让Python虚拟机在进行运算时无法有效利用多核心。对于纯计算任务,它永远最多只能榨干单个CPU核心。如果要突破这个瓶颈,就必须fork出多个子进程来分担计算任务。而对于IO密集型任务,CPU使用率往往是极低的。
第四部分 调度算法
1 调度的基本准备有哪些?什么是系统吞吐量?
什么是周转时间?什么是等待时间?
什么是响应时间?
1)有系统吞吐量,周转时间,等待时间,响应时间等。
2)系统吞吐量表示单位时间内cpu完成的作业数量。
3)周转时间=作业完成时间 - 作业到达时间
4)等待时间=进程处于等待处理器的时间之和
5)响应时间=用户提交请求到系统首次产生响应所用的时间。
2 有哪些调度算法?短作业优先调度算法有什么特点?
1)先来先服务,短作业优先,优先级,高响应比优先,时间片轮转等
2)短作业优先的平均等待时间,平均周转时间最少。
第五部分 死锁
1什么是死锁?死锁产生原因有哪些?
死锁产生的必要条件有哪些?
1)死锁是多个进程竞争资源造成的一种僵局。
2)系统资源竞争+进程推进顺序非法
3) 必须同时满足下面4个条件
互请不环。
互斥条件: 进程对锁分配资源进行排他性控制。
请求和保持条件: 进程每次申请它所需要的部分资源,在等待新资源的同时,进程继续占有已分配资源
不剥夺条件: 进程锁获得资源未使用完成前不能被其他进程剥夺
循环等待条件: 存在进程资源的循环等待链,每个进程已获得资源被链中下一个进程所请求。
2 死锁的处理策略有哪些?什么是预防死锁?
什么是避免死锁?死锁检测与解除是怎样的?
1)预防,避免,死锁检测与解除。
2)预防死锁就是破坏死锁4条件中若干个。
3)避免死锁可以在资源分配过程中,通过某种方法避免系统进入不安全状态。
例如银行家算法。
4)死锁检测与解除
可以通过资源分配图来检测死锁,
通过:资源剥夺,撤销进程,进程回退来解除死锁。
第六部分 内存管理
1 内存管理有什么功能?什么是逻辑地址空间?
什么是物理地址空间?
1)内存分配与回收,地址转换等。
2)编译后,每个目标模块的地址从0号单元开始编址,则称该目标模块的相对地址为逻辑地址。
链接程序将各个模块链接为目标程序时,按各个模块相对地址构成从0号单元开始编址的逻辑地址空间。
3)物理地址空间是内存中物理单元的集合,是地址转换的最终地址。
将可执行代码装入内存,需要通过地址转换将逻辑地址转换为物理地址,这个过程称为地址重定位。
2 内存分配管理方式有哪些?什么是连续分配方式?什么是非连续分配方式?
1)内存分配方式包括连续分配/非连续分配 管理方式。
2)连续分配方式为一个程序分配一个谦虚内存空间,包括:
单一连续分配,固定分区分配,动态分区分配。
3)非连续分配方式允许程序装入到不相邻内存分区中,根据分区大小是否固定分为:
分页/分段分段存储管理方式。
分页: 根据运行作业是否要把所有页面都装入内存才能运行分为
基本分页/请求分页 存储管理方式
3 基本分页存储管理方式思想是怎样的?平均的碎片大小是多少?
什么是页面和页面大小?基本分页存储管理方式的地址结构是怎样的?
什么是页表?
1)把驻村空间分为大小相等且固定的块,块作为主存的基本单位。
每个进程以块为单位进行划分和申请。
2)进程只会为最后一个不完整的块申请一个主存块空间,每个进程
平均只产生半个块大小的内部碎片。
3)页是进程中的块,块是外存以同样单位划分。
页面大小:是2的整数幂。页面大小应该适中。
4)地址结构=页号P + 页内偏移量M
假设地址长度为32位,0~11位为页内地址,即每页大小为2^12=4*2^10=4KB,
12到31位为页号,地址空间最多允许有2^20页。
样例:
31 12 11 0
[ 页号P ][ 页内偏移量M ]
5)页表记录页面在内存中对应的物理块号。实现从页号到物理块号的地址映射。
4 对于一个内存地址是32位,内存页是8KB的系统。
0X0005F123这个地址的页号与页内偏移分别是多少?
解: 分页地址=页号 + 页内偏移量。
内存页8KB=2^13B,所以页内偏移量占据13位,即0到12位,
页号占据32-13=19位。
0X0005F123转换为二进制为
0000 0000 0000 0101 1111 0001 0010 0011
前19位对应页号即:
0000 0000 0000 0101 111
即
000 0000 0000 0010 1111
转换后是十进制是:
32 + 15 = 47即为页号
页内偏移量
1 0001 0010 0011
对应十进制是
3 + 32 + 256 + 4096 = 291 + 4096 = 4387
综上:
页号为47,页内偏移量为4387
5 什么是基本分段存储管理方式?其地址结构是怎样的?
页式系统与段氏系统的不同点是什么?
1)按照用户进程中自然段划分逻辑空间。
2)逻辑地址=段号S + 段内偏移量W
样例:
下面段号为16位,段内偏移量为16位,则一个作业最多可有2^16=65536个段,
最大段长=2^16=64KB。
31 16 15 0
[ 段号S ][ 段内偏移量W ]
段内偏移量决定每个段的大小,同样的,页内偏移量决定每个页的大小。
3)页式系统中,页号与业内偏移量对用户透明,
段氏系统中段号和段内偏移量必须由用户显示提供。
6 段页式管理方式原理是怎样的?其地址结构是怎样的?
如何实现地址变换?
1)页式存储能提供内存利用率,段氏存储能反映程序逻辑结构。
段页式系统: 作业地址空间被分成逻辑段,每段有段号,将每段分成大小固定的页。
2)地址结构=段号 + 页号 + 页内偏移量。
3) 每个进程有段表,每个分段有页表。
段表=段号 + 页表长度 + 页表起始地址
页表=页号 + 块号
段表寄存器=段表起始地址 + 段表长度
7 什么是虚拟存储器?其本质是什么?
虚拟内存的实现方式有哪些?虚拟内存实现所需要的条件有哪些?
段页式虚拟存储器有哪些优点?
1)基于局部性原理,通过:部分装入内存,就可以启动程序执行
当所访问信息不再内存,部分调入内存。
可将内存上暂时不用内容换出,为用户提供一个似乎比实际内存大得多的存储器。
2)虚拟存储器=部分装入 + s请求调入 + 置换
3)请求 分页/分段/段页式 存储管理。
4)内存,外存,页表作为数据结构,中断,地址变换(逻辑地址到物理地址)
5)段氏优点: 程序模块化编写,段共享和保护,执行时动态链接。
页式优点: 主存储器利用率高。
8 请求分页管理方式有哪些功能?请求分页的置换算法有哪些?
1)在基本分页基础上添加:请求调页 + 页面置换。
2)最佳置换 + 先进先出 + 最近最久未使用(LRU)
9 什么是最佳置换算法?
1)所选择的淘汰页面是以后永不使用或最长时间不再被访问的。
因为无法预知而无法实现。
根据后面状态确定当前淘汰的部分。
10 什么是先进先出页面置换算法?会产生什么问题?
1)淘汰最早进入内存的页面。
2)所分配的物理块数增大而故障树不减反增的Bleady异常。
11 什么是最近最久未使用置换算法?请举例?
如何实现?
1)选择最近最长时间未访问的页面淘汰。
依据前面判断当前淘汰的页面。
2)
假设位进程分配3个物理块,有如下页面号引用串:
7,0,1,2,0,3,0,4,2,3
访问页面 7 0 1 2 0 3 0 4 2 3
物理块1 7 7 7 2 2 2 2 4 4 4
物理块2 0 0 0 0 0 0 0 0 3
物理块3 1 1 1 3 3 3 2 2
缺页否 Y Y Y Y N Y N Y Y Y
3) LRU是堆栈类算法,需要寄存器和栈实现。
11 什么是抖动?什么是工作集?
1)频繁的页面调度行为。
2)工作集是某段时间间隔内进程要访问的页面集合。
参考:
王道程序员求职宝典
https://blog.csdn.net/qingyuanluofeng/article/details/97882309
https://blog.csdn.net/wei_cheng18/article/details/79658209
https://blog.csdn.net/qq_38410730/article/details/81488145
https://www.cnblogs.com/hoojjack/p/10846010.html
http://blog.sina.com.cn/s/blog_3df05c220102ydlj.html
https://www.cnblogs.com/maxigang/p/9041080.html
https://www.nowcoder.com/questionTerminal/e72c6b33bb874d27883b5254e58aa403?orderByHotValue=1&page=1&onlyReference=false