1、进程与线程
进程——是指在系统中正在运行的一个应用程序,是系统进行资源分配的最小单位,且每个进程拥有独立的地址空间。
线程——是进程的一个实体,是CPU调度和分派的基本单位。它是比进程更小的能够独立运行的基本单位。
多进程——允许多个任务同时执行。
多线程——允许单个任务分成不同部分执行。
2、进程和线程的关系
一个线程只能属于一个进程,而一个进程可以拥有多个进程,至少拥有一个进程。
系统将资源分配给进程,同一进程下的所有线程共享该进程的所有资源。
处理机分配给线程,即真正运行在处理机上的是线程。
线程在执行过程中,需要协作同步。不同进程的线程间,要利用消息通信实现同步。
3、进程和线程的区别
线程是程序执行的最小单位,进程是资源分配的最小单位。
同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
同一进程的线程共享本进程的资源,而进程之间的资源时独立的。
进程和线程都可以并发执行。
一个进程崩溃后,在保护模式下不会对其他进程产生影响;但是一个线程崩溃,整个进程就会崩溃,所以多进程比多线程健壮。
在创建和撤销进程时,系统都要为其分配和回收资源,导致进程切换时消耗的资源明显大于线程切换
4、进程间的通信方式
管道通信
有名管道(FIFO)——一种半双工的通信方式,它允许无亲缘关系进程间的通信。
- 优点
- 可以实现任意关系的进程间的通信。
- 缺点
- 长期存于系统中,使用不当容易出错。
- 缓冲区有限。
- 优点
无名管道(PIPE)——一种半双工通信,只能在具有亲缘关系的进程间使用。
- 优点
- 简单方便
- 缺点
- 局限于单向通信
- 缓冲区有限
- 只能在具有亲缘关系的进程间通信。
- 优点
信号量(Semaphore)
一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
信号量用于进程间同步,若要在进程间传递数据,则需要结合共享内存。
信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作。
优点
- 可以同步进程
缺点
- 信号量有限
- 信号(Signal)
- 一种比较复杂的通信方式,用于通知接受进程某个事件已经发生。
消息队列(Message Queue)
消息的连接表,存放在内核中,并由队列标识符标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接受进程,进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询。
优点
- 可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题。
缺点
- 信息的复制需要额外消耗CPU的事件,不适用于信息量大或操作频繁的场合。
共享内存(Shared Memory)
指两个或多个进程共享一个给定的存储区。
共享内存是最快的一种进程通信方式,因为进程是**直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量和共享内存通常结合在一起使用。
Socket(套接字)
- 可用于不同机器间的进程通信。
- 适合于客户端与服务器断的信息实时交互。
- 传输数据时间短、效率高。
5、死锁是什么?
- 死锁是指多个进程循环等待其他进程占有的资源而无限僵持下去的局面。即如果没有外力条件,那么死锁涉及到的各个进程都将永远处于封锁状态。当两个或两个以上的进程,同时对互斥资源提出请求时,有可能导致死锁。
6、死锁产生的四个必要条件
互斥条件
- 某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有。这种独占资源有CD-ROM驱动器,打印机等,必须等待占有该资源的进程主动释放资源之后,其他进程才能够占有。这是由资源本身属性所决定的。(独木桥就是独占资源,两头的人不能同时过桥)
不可剥夺条件
- 一个进程所获得的资源未使用完毕之前,其他资源申请者不能强行从资源占有者手中夺取资源,而只能等待资源占有者主动释放。(还是独木桥,双方过桥,不能强行将对方推下桥或强迫对方后退,只能等一方过完桥,空出桥面后,另一方再过桥)
请求和保持条件
- 进程至少已经占有一个资源,但是又申请新的资源。由于新资源被其他进程占有,此时该进程阻塞,但是该进程在等待新资源时,并没有释放已经占有的资源。(又是独木桥,甲已经走过一段桥面,乙也已经走过一段桥面,甲乙双方既不能前进,也不想后退)
循环等待条件
- 存在一个进程等待序列,{p1,p2,...,pn},其中p1等待p2所占用的某一资源,p2等待p3所占用的某一资源,...,pn等待p1所占用的某一资源(最后也是独木桥,类似于前面的情况,甲等待乙后退,乙等待甲后退)。
7、进程和线程占有的资源
进程独有的资源
- 地址空间、堆、全局变量、栈、寄存器
进程共享的资源
- 代码段、公共数据、进程目录、进程ID
线程独有的资源
- 线程栈、寄存器、程序计数器、状态字
线程共享的资源
- 堆、地址空间、全局变量、静态变量
8、什么是僵尸进程和孤儿进程?如何避免僵尸进程?
僵尸进程
- 进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程就是僵尸进程。
孤儿进程
- 父进程退出,还在运行的子进程就是孤儿进程,孤儿进程将被init进程(进程号为1)收养,并由init进程对他们完成状态收集工作。
避免僵尸进程的方法:
fork两次,用孙子进程完成子进程的任务。
用wait()函数使父进程阻塞。
使用信号量,在signal handler中调用waitpid,这样父进程不用阻塞。
9、python中多进程和多线程的使用场景?
- 多进程适合在cpu密集型操作(cpu指定比较多,如位数多的浮点运算)
- 多线程适合在IO密集型操作(读写数据操作较多的,如爬虫)
10、同步、异步、阻塞、非阻塞的概念?
同步——多个任务之间有先后顺序,一个执行完下个才能执行。
异步——多个任务之间没有先后顺序,可以同时执行。有时一个任务可能在必要的时候获取另一个同事执行的任务的结果,这就是回调。
阻塞——如果卡住了调用者,调用者不能继续往下执行,就是调用者阻塞了。
非阻塞——如果不会卡住,可以继续执行,就说明是非阻塞的。
同步和异步是相对于多任务而言,阻塞非阻塞相对于代码执行而言。
11、并发和并行的概念?
并发——在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情况。
并行——在同一时刻多个任务同时运行。
线程是并发,利用threading库实现。
进程是并行,利用multiprocessing实现。
并行——多进程——CPU密集型
并发——多线程——IO密集型