一、并发与并行
并行:多个计算机核心在同时处理多个任务,这时多个任务间是并行关系
并发:同时处理多个任务,但是内核在多个任务间不断地切换,达到好像都在处理运行的效果,但实际一个时间点内核只能处理其中一个任务。
二、进程
进程与线程是实现多任务编程的实施方案
进程与线程:
程序:是一个可执行的文件,是静态的占有磁盘空间,不占有计算机的运行资源
进程: 是一个动态过程的描述,占有计算机的资源,有一定的生命周期
*同一个程序的不同运行过程是不同的进程,占用资源和生命周期都不一样。
1、进程的创建流程:
(1)用户空间通过运行程序或者调用接口发起创建进程
(2)操作系统接受用户请求,开始创建进程
(3)操作系统分配计算机资源,确定进程状态,开辟进程空间等工作
(4)操作系统将创建好的进程提供给应用程序使用
2、关于进程的概念
PCB(进程控制块): 在内存中开辟的一块空间,用来记录进程的信息。
进程控制块是操作系统查找识别进程的标志。
cpu时间片:如果一个进程占有计算机核心,我们称为该进程占有计算机cpu时间片
*多个任务之间是争夺cpu的关系
*谁占有cpu最终是操作系统决定
进程的状态:
三态 :
*就绪态:进程具备执行条件,等待系统分配资源
*运行态:进程占有cpu处于运行态
*等待态:进程暂时不具备执行条件,阻塞等待满足条件后再执行
五态(三态基础上增加新建态,终止态):
*新建态:创建一个新的进程,获取资源的过程
*终止态:进程执行结束,资源释放回收的过程
进程的特征:
(1)进程之间运行互不影响,各自独立运行
(2)进程是操作系统资源分配的最小单位
(3)每个进程空间独立,各自占有一定的虚拟内存
三、多进程编程
import os
pid = os.fork()
功能:创建新的进程
参数:无
返回值:失败返回一个负数,
成功:在原有进程中返回新的进程的PID号,在新的进程中返回0
*子进程会复制父进程全部代码段,包括fork之前产生的内存空间
*子进程从fork的下一句开始执行,与父进程互不干扰
*父子进程的执行顺序是不一定的,父子进程共用一个终端
*父子进程通常会根据fork返回值的差异选择执行不同的代码,所以if结构几乎是fork的固定搭配
*父子进程空间独立,操作的都是本空间的内容,互不影响
*子进程也有自己的特特性,比如PID号,PCB,命令集等
进程相关的函数:
获取进程
PID:os.getpid()
功能:获取当前进程的进程号
返回值:返回进程号
os.getppid()
功能:获取当前进程父进程的的PID号
返回值:返回进程号
os._exit(status)
功能:进程退出
参数:进程的退出状态
sys.exit(status)
功能:进程退出
参数:数字表示退出状态,不写默认为0
字符串,表示退出时打印的内容
*sys.exit() 可以通过捕获SystemExit异常阻止退出
孤儿进程:父进程先于子进程退出,此时子进程称为孤儿进程
*孤儿进程会被操作系统指定的进程收养,系统进程就成为孤儿进程的新的父进程
僵尸进程:子进程先于父进程退出,但是父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程
*僵尸进程会存留少量PCB信息在内存中,大量的僵尸进程会消耗系统资源,应该避免僵尸进程的产生
四、如何避免僵尸进程产生
*处理子进程退出状态
pid,status = os.wait()
功能:在父进程中阻塞等待处理子进程退出
返回值:pid 退出的子进程的PID号
tatus 获取子进程的退出状态
pid,status = os.waitpid(pid,option)
功能:在父进程中阻塞等待处理子进程退出
参数:pid -1 表示等待任意子进程退出
>0 表示等待对应PID号的子进程退出
option 0 表示阻塞等待
WNOHANG 表示非阻塞
*让父进程先退出
(1)父进程创建子进程等待子进程退出
(2)子进程创建二级子进程后立即退出
(3)二级子进程成为孤儿
五、multiprocessing模块创建进程
1、需要将要执行的事情封装为函数
2、使用multiprocessing模块中Process类创建进程对象
3、通过对象属性设置和Process的初始化函数对进程进行设置,绑定要执行的函数
4、启动进程,会自动执行进程绑定的函数
5、完成进程的回收
Process()
功能:创建进程对象
参数:name 进程名称 Process-1
target 绑定函数
args 元组 给target函数按照位置传参
kwargs 字典 给target函数按照键值对传参
p.start()
功能:启动进程
*target函数会自动执行,此时进程真正被创建
p.join([timeout])
功能:阻塞等待回收子进程
参数:超时时间
*使用multiprocessing创建子进程,同样子进程复制父进程的全部代码段,父子进程各自执行互不影响,父子进程有各自的运行空间
*如果不使用join回收子进程则子进程退出后会成为僵尸进程
*使用multiprocessing创建进程往往父进程只是用来创建进程回收进程