进程和线程
一家公司就类似一个程序, 进程是公司下属部门,是资源分配的最小单位, 线程则像是部门下属员工
部门之间通信需要建立通道(管道\共享内存)或者公告板(消息队列),
员工之间通信,基本靠吼(全局变量),牛逼的员工也可做到和一个部门(进程)同样的能力
概念
1、多任务编程
1、意义 : 充分利用计算机的多核资源,同时运行多个任务,提高程序执行的效率
2、实现方法 : 多进程、多线程
2、概念
1、并发 : 同时处理多个任务,交替进行,内核在任务间不断切换,达到好像多个任务同时被执行的效果,实际上在每一时刻里,只有一个任务在占用cpu
2、并行 : 同一时间同时进行多个任务,一起执行,多个任务利用计算机的多核资源同时执行,此时多个任务之间是并行关系
3.在计算机系统中,并行和并发是同时存在的
进程和程序的定义和区别
1、进程 : 程序在计算机中的1次运行过程
2、程序 : 可执行文件,静态的,占用磁盘
3、区别 : 进程是一个动态的过程,占用计算机资源(CPU、内存),有生命周期
程序 : 为1个文件,战友外存储器(磁盘)
进程的诞生
1、用户通过启动程序,或者调用进程创建接口发起请求
2、操作系统接收用户请求,开始创建进程
3、操作系统分配计算机资源,确定进程状态,开辟空间等
4、把进程提供给用户使用
进程
1、cpu时间片
如果一个进程占用cpu,则称这个进程在CPU事件片上或称这个程序得到了CPU事件片,谁获取到了CPU时间片,谁就可以执行,进程等待
2、PCB(进程控制块)
在内存中开辟的一块空间,存放进程的基本信息,也是操作系统调用进程的重要标志.
3、进程ID(PID)
操作系统为每一个进程分配一个不重复的ID号,该进程在系统中的标识
查看进程信息 : ps -aux
4、父子进程 :
系统中每个进程都有唯一的父进程
1、查看进程树 : pstree
2、示例 : 写一个程序,每隔两秒打印一下时间
3、1个终端运行程序,在另一个终端执行 ps -aux
5.进程状态
1、三态 :
就绪态
具备执行条件,等待系统分配CPU事件片
运行态
占有了cpu时间片
等待态
进程暂时祖阻塞,不具备执行条件
2、五态 :
新建态:
创建新进程获取资源的过程
终止态
结束进程,释放资源的过程
3、查看进程状态 : ps -aux 查看STAT列
4、进程的优先级
1、作用 : 决定进程的优先权限和占有资源的优先程度
2、Linux优先级范围(40级) -20~19 越小越高
默认优先级为0
3、查看优先级的命令 : top
NI 这一列就是优先级 shift -+翻页
指定优先级 : nice --20 python3 xxxx
进程状态
查看进程状态 : ps -aux 查看STAT列
S : 等待态 (sleep,可中断等待态,阻塞函数),可中断阻塞(阻塞函数)
D : 等待态(不可中断,系统进程),不可中断阻塞
T : 暂停态(后台程序,暂停执行,但是没有结束)
R : 运行态
Z : 僵尸进程
< : 较高的优先级
N : 较低的优先级
+ : 前台进程(在终端运行,能够被终端控制的进程)
小技巧
如何后台执行程序
firefox & - 让程序在后台运行
如何杀死进程
kill -9 PID进程号
如何查找进程PID号
ps -aux | grep '进程名'
查看进程信息 : ps -aux
查看进程树 : pstree
进程的运行特征
1.可使用计算机多核资源
2.计算机分配资源的最小单位(CPU、内存)
3、每个进程空间独立,有自己的资源
4、进程之间的运行互不干扰,相互独立
利用OS模块创建进程
1、方法名 : pid = os.fork()
功能 : 创建新的进程
返回值
1、创建进程失败 : 返回负数
2、创建进程成功
1、原进程中返回新进程的PID号
2、新进程中返回0
2、注意
用fork()执行结果可能不一致,因为虽然是父子进程,但不存在谦让关系,谁先抢到cpu时间片谁先执行
各个进程间,资源空间相对独立,不会互相干扰
3.关于fork()
子进程从fork()下一句开始
父子进程各自独立运行,运行顺序不一定:
if 结构和fork()固定搭配
子进程会复制父进程全部代码和空间,包括fork()之前的资源
父子进程空间互不影响,各自修改各自空间内容
4.进程函数(os)
os.getpid()
获取当前进程的PID号
os.getppid()
获取父进程的PID号
os._exit(status)
功能 : 退出当前进程
参数 : status 0 正常 1 异常
示例 : os._exit(0)
sys.exit(status)
功能 :退出当前进程
参数 : 默认为0 ,可以已传字符串并输出在终端上
示例 : sys.exit('进程已退出')
5、孤儿进程
父进程先于子进程退出,此时子进程就是孤儿进程(会被系统进程收养)
6、僵尸进程 : Z
1、子进程先结束,而且父进程没有处理子进程退出行为,此时子进程为僵尸进程
2、大量僵尸进程后果: 虽然结束,但是会存留部分进程信息在内存中,耗费系统资源
避免僵尸进程的方法
1、让父进程来处理子进程
pid,status = os.wait()
功能 : 分进程中阻塞,等待子进程退出并处理
返回值 : pid - 已退出的子进程的PID好
status - 子进程的退出状态(0正常,1异常)
2、二级子进程
让一级子进程先退出,二级子进程变为孤儿进程,被系统进程收养,再让父进程处理一级子进程
的退出,通过将一级子进程直接杀死,使得父进程和二级子进程互无关联,而避免了僵尸进程的出现
if __name__ == '__main__' :
pid = os.fork()
if pid <0:
print('一级进程创建失败')
elif pid == 0:
p = os.fork()
if p < 0:
print('二级进程创建失败')
elif p == 0:
print('二级进程创建成功')
copy2() #事件2 二级子进程
else:
sys.exit('一级子进程退出')
else:
pid,status = os.wait()
print('一级子进程处理完毕')
copy1() # 事件1 父进程
multiprocessing模块
multiprocessing
一、基本格式
1、导入模块
form multiprocessing import Process
2、将需要执行的进程事件封装为函数
def fun()1… # 不能用input()函数
3、使用Process类生成进程对象,并关联相关函数
if name == ‘main’
p = Process(target = fun1)
4、通过进程对象启动进程(satrt()),自动执行进程函数
p.start()
5、回收进程(避免产生僵尸进程)
p.join()
二、process 类
功能 :
创建进程对象
参数(传给(__init(…))
1.targer = 函数名() : p =process(tager = fun1)
2 . name = ‘进程名’ : 给进程起名字,默认Process -1
3.args = (元祖) : 元祖传参(按照位置给target函数传参)
4. kwargs = {字典} : 字典传参(按照键值对给target传参)
例子:
def fun1(name,age):
…
p=Process(target = fun1,agre(‘郭德纲’,‘45’))
p = process(target = fun1,kwargs =({“name”:“于谦”,“age” : 45})
p.join([timeout]) : 阻塞等待回收子进程,超时时间,如果超过时间,则解除阻塞
三、Process 类创建进程
1、同样子进程复制父进程全部空间,父子进程互不影响
2、join()作用:
阻塞,处理子进程,等所有子进程结束后执行父进程后面语句
3、start()后面最好加join(),避免子进程先结束为僵尸进程
4、父子进程同时做事在start()和join()中间写代码
四、多进程
1、父进程一般只用来创建子进程和回收子进程,具体事务让子进程来做
父进程 : 负责创建进程、回收进程
子进程们 : 各自执行各自的功能函数
##牺牲了1个进程(父进程)的代价来处理僵尸进程
2、multiprocessing中父进程更方便的创建多个子进程执行更多个事件,父进程往往将事件交由子进程去完成
五、进程中函数的传参
1、元祖传参
args=()
2、字典传参
kwargs = {‘参数名’:要传的值}
6、进程对象 P 属性
1、p.name :进程名称
2、p.pid : 进程pid号
3、p.is_alive : 进程状态
4、p.daemon : 守护进程,默认False,主进程结束,不影响子进程
设置为true ,主进程退出,子进程全部结束
5.daemon不要和join同时使用
守护进程一般为系统后台进程
生命周期很长(开/关机)
7.自定义进程类
1、使用情况 : 使用类将一系列功能进行封装,完成比较复杂的功能
2、使用流程
1、集成Process类, Process类中属性和方法就有了
2、编写自己的__init__()函数
3、重写run方法,完成功能的逻辑调用(名字不能变)
4、创建实例化对象
5、用对象调用一个start()来创建新进程, 自动执行run()方法
6、用进程对象调用join()方法回收进程
8、进程池
1、多进程优缺点
1、优点 : 利用多核资源, 同时执行多任务, 提高效率
2、缺点 : 进程创建和删除需要消耗较多的系统资源,
大量进程频繁创建和删除会给系统带来压力
2、进程池
1、产生原因 : 应对大量任务,需要多进程完成, 需要频繁创建和销毁进程的情况
2、原理 : 创建一定量的进程作为进程池, 用来处理事件, 事件处理完成后进程不退出, 而是继续等待处理其他事件, 直到所有待处理事件处理完成后统一销毁, 增加了进程的重复利用率,降低资源消耗.
3、使用流程
1、创建进程池, 放入时长数量的进程
2、将要做的实景封装成函数,放入进程池的等待队列
3、进程池中国的进程不断执行任务,直到全都被执行
4、关闭进程池, 回收进程
4、常用方法
1、类名 : from multiprocessing import pool
2、pool = Pool(porcesses = n) 创建n个进程
功能 : 创建进程池对象
参数 : 指定进程池中进程数量,默认根据系统自动判定(可不写,根据cpu核心数量)
3、想进程池中添加任务的方法
1.poo.apply_async(func,args,kwds)
功能 : 放入要执行的事件函数(异步非阻塞)
解释 : 异步, 交代完任务就去做别的,不会等
参数 : func 事件函数
args 元祖传参
kwds 字典传参
2.poo.apply(func,args,kwds)
功能 : 放入要执行的事件函数(同步阻塞)
解释 : 同步,进程池中只能有1个进程在执行,退出1个,进来1个
参数 : func 事件函数
args 元祖传参
kwds 字典传参
返回值 : 返回函数事件对象(获取到func返回值)
3、poo.map(func,iter)
功能 : 放入要执行的事件函数(同步阻塞)
解释 : 同步,进程池中只能有1个进程在执行,退出1个,进来1个
参数 : func 事件函数
args 元祖传参
kwds 字典传参
返回值 : 返回函数事件对象(获取到func返回值)
获取方法 :
1.robj = pool.apply_async(func,args=(i,))
2.robj.get()
4、pool.close()
功能 : 关闭进程池, 无法再添加新的任务
5、pool.join()
功能 : 阻塞等待回收进程池