进程: 进程就是程序在计算机中一次执行过程.
进程和程序的区别:
程序是一个静态文件的描述,不占计算机的系统资源
进程时一个动态的过程,占有cpu内存资源,有一定的生命周期.
*同一个程序的不同执行过程即为不同的进程
问题1 什么决定了进程的创建
用户通过应用层程序进行进程的创建申请,
调用操作系统接口进行进程创建.
告知系统内核创建新的进程提供给应用层使用.
问题2 进程如何占有cpu
1.同一个内核同一时刻只能运行一个进程
2.多个进程对内核资源进行抢占,由操作系统内核进行分配.
3.哪个进程占有计算机内核,我们称为该进程占有cpu的时间片
问题3 进程在运行过程中的心态和附带内容
1. pcb(进程控制块):在linux和unix操作系统中,进程创建后会在内存中开辟一块空间存放进程的相关信息,这个空间称为pcb.
2. PID:在操作系统中进程的唯一标识. 是一个大于0的正整数,由系统自动分配.
3. ps -aux 查看进程信息命令
4. 虚拟内存: 每个进程占有4G内存地址空间,这里的内存指的是虚拟内存.
5. 进程状态:
三态:
就绪态 进程具备运行条件,等待系统分派处理器以便运行
运行态 进程占有cpu处于运行状态
等待态 又称为阻塞态或睡眠态,指进程不具备运行条件,正在等待某些条件的达成.
五态:
新建态:创建一个进程的过程,直接表现为;执行某个程序或者在程序中创建新的进程.
终止态:进程执行结束,完成回收的过程.
进程stat:
D 等待态 不可中断等待态
S 等待态 可终端等待态
T 等待态 暂停
R 运行态
Z 僵尸态
+ 前台进程
N 低优先级的进程
< 高优先级的进程
l 有进程链接
s 绘画组
进程的优先级:
优先级往往决定了一个进程的执行权限和占有系统资源的优先程度.
linux 系统中优先级范围 -20 ----19 -20 优先级最高
用户创建进程默认优先级为0
top : 动态查看系统进程的运行状状态 < > 翻页
nice: 以指定的优先级运行某个进程
eg: nice -9 ./while.py 以9的优先级运行程序
sudo nice --9 ./while.py 以-9的优先级运行程序.
renice n pid :修改一个正在运行的进程的优先级 更改程序运行的优先级.
eg: renice 8 4277 将4277号进程优先级改为8
父子进程:
在系统中除了初始化进程之外每个进程都是由父进程创建的,
每个进程又一个唯一的父进程,可能有多个子进程.
需求: 两件不相关的事情希望同时来做
方案1: 写两个进程,分别承担不同的事情,各自执行.
分析: 1.两个程序比较麻烦
2.无法确定两个程序应该在什么时间开始运行
方案2: 写一个程序, 在程序中指定位置调用接口来创建新的进程.
实现方法:
通过os.fork()函数实现.
fork()
*fork是os系统模块只能在linux或unix系统中使用.
功能: 创建一个新的进程.
参数: 无
返回值: < 0 表示进程创建失败
==0 在子进程中fork的返回值为0
> 0 在父进程中fork的返回值大于0
测试1 : 父进程中的fork之前的内容,子进程 同样也会复制但是父子进程空间内容的修改不会相互影响.
测试2: 父子进程在执行上互不影响,理论上不一定谁先执行.
测试3:子进程虽然复制父进程的空间,但是;也有直接独特的特性,比如自己的pid,进程控制块,进程栈等.父进程中fork的返回值即为创建的子进程的pid号.
进程相关的函数
os.getpid()
功能: 获取当前进程的pid号
os.getppid()
功能: 获取当前进程父进程的pid号
结束进程:
os._exit(status)
功能: 结束一个进程
参数: 一个数字表示进程的退出状态,通常0表示正常退出,其他数字表示非正常退出.
sys.exit([status])
功能: 结束一个进程
参数: 一个数字表示退出进程的状态,同上
可以是一个字符串,在进程退出时会打印这个字符串.
僵尸进程:
子进程先于父进程退出,而父进程没有对子进程的退出作出相应的处理,此时子进程就会变为僵尸进程.
影响: 进程退出后,仍有部分信息残留在内存中占用空间,大量的僵尸进程会影响系统运行,所以应该尽量避免僵尸进程的产生.
孤儿进程:
父进程先于子进程退出,此时子进程就会变为孤儿进程.
影响:
当一个进程变为孤儿进程,系统会自动的使用一个进程成为孤儿进程的父进程.当孤儿进程退出时,该系统进程会自动处理孤儿进程,使其不会成为僵尸进程. 所以孤儿进程对系统资源没什么影响.
处理僵尸进程的方法:
1. 让父进程先退出.(不好控制)
2. 父进程处理子进程的退出
os.wait()
功能: 等待子进程退出进行处理.
单数:无
返回值: 返回一个包含两个元素的元祖,第一个是退出的子进程的PID号,第二个是是子进程的退出状态.
*wait 是一个阻塞函数. 即进程处于等待状态,等待某种条件的达成才会继续运行.
os.waitpid(pid,option)
功能: 同wait 处理子进程退出使其不会变为僵尸进程.
参数: pid -1 表示等待任意子进程退出
> 0 表示等待指定进程号的子进程退出.
option 0 表示阻塞等待, 一直等到条件满足
WNOHANG: 表示非阻塞状态.
返回值: 同wait()
3. 创建二级子进程处理.
4. 在父进程中使用信号处理的方法忽略子进程发来的信号.
signal(SIGCHLD,SIG_IGN)
更方便高效的进程创建方法:
multiprocessing模块(标准库模块)
创建进程的步骤:
1.将要完成的事件封装成函数
2.使用multiprocessing提供的接口函数创建进程
3.使新的进程和指定的函数相关联去完成函数中的工作.
4.对进程进行回收处理.
*函数当赋给process的target变量后函数内容就是对应进程的进程内容,
此时函数才有特殊性
*多个子进程和父进程之间的执行相互不影响.
创建子进程
Process()类
参数: target 指定要绑定的函数
name 给创建的进程命名
args 需要一个元祖,给target指定函数传参,给target指定的函数按位置传参
kwargs 需要给一个字典,给target指定的函数按键值传参.
Process()类-----》 属性方法.
print('进程名称:',p.name)
print('进程pid:',p.pid)
print('进程状态',p.is_alive())
启动子进程
start()
*start() 时才真正的创建子进程,而不是Process时创建.
回收子进程
join([timeout])
timeout:
设置最长阻塞时间,如果超过这个时间还没有子进程退出则不再继续等待.
*内核会帮助应用层记录子进程的退出状况,当使用join函数时内核会及时返回进程状态给应用层进行处理.
p.daemon
默认值为False 表示主进程运行结束后 不会影响子进程的运行,直到子进程运行完,进程才会结束.
如果设置为True,则主进程运行完毕所有子进程也不再运行一起退出.
*该属性的设置必须要在start()前
*该属性的设置并不是 将进程设置为linux/unix中的守护进程
守护进程:
生命周期长,与前端控制台无关,后台运行,一般用作操作系统进程或者自动化进程运行.
多进程编程
优点: 可以并行的执行多个任务,提高运行效率 空间独立,数据安全.
创建方便,
缺点: 进程的创建和销毁过程需要消耗较多的计算机资源.
在需要频繁的创建和删除较多进程的情况下,资源消耗过多,不适宜使用多进程完成任务.
进程池技术
1.创建进程池,在池内放入合适数量的进程
2.将事件加入进程池的等待队列
3.使用进程池内的进程不断的执行等待事件
4.所有事件处理结束后关闭回收进程池
Pool()
功能: 创建进程池
参数:processes:进程池中进程的数量
apply_async()
功能: 以异步的方式将要执行的事件放入进程池
参数: func: 要执行的事件
args: 给函数按位置传參
kwds:给函数按照键值传參
返回值:返回事件fun执行后的返回值对象,可以通过调用get()函数获取函数的return内容.
apply()
功能:按照顺序添加要执行的事件,执行一个添加一个.s
参数:同上
close()
功能: 关闭进程池,使其不能再加入新的事件
join()
功能: 阻塞等待进程池将事件都执行结束后回收进程池.
map()
功能: 类似于内建函数map, 将第二个函数参数的迭代对象中的数据逐个带入第一个函数作为参数,只不过兼顾了apply_async功能,将函数放入进程池.
r = pool.map(fun, test) ====>
for I in test:
pool.apply_async(fun,(I,))
创建自己的进程类:
class Process(…):
self.attr = test
def test(self):
pass
class myProcess(Process):
def test(self):
…
1.继承Process类以获取原有的属性,
2.实现自己需要的功能部分
3.使用自己的类创建进程即可
进程间通信
管道
在内存中开辟一个管道空间,对多个进程可见.在通信形式上形成一种约束.
Linux文件类型 b(块驱动文件)c(字符设备文件输入输出相关)d(目录) -(普通文件) l(链接)s(套接字)p(管道)
multiprocessing —》 Pipe
《计算机原理》
Pipe(duplex)
功能: 创建一个管道
参数: duplex 默认为True 表示管道为双向管道.
如果设置为False 则表示管道为单向管道.
返回值:
返回两个管道流对象.分别表示管道的两端.
如果参数为True(默认) 两个对象均可发送接收.
如果为False 时则第一个对象只能接受,第二个对象只能发送.
*向管道发送数据使用send()函数,从管道接受数据使用recv()函数
*recv()函数为阻塞函数,当管道中数据为空时会阻塞.
*一次recv()只能接受一次send()的内容.
*send()可以发送字符串数字列表等多种类型数据.
消息队列
multprocessing —> Queue
在内存中开辟一个队列模型,用来存放消息.任何拥有队列对象的进程都可以进行消息的存放和取出.
#创建一个消息队列对象
q = Queue()
功能: 创建一个消息队列对象
参数: maxsize 默认为0 表示消息队列可以存放的消息由系统自动分配的空间而定.
> 0 正整数,表示队列中最多存放多少条消息.
返回值: 消息列对象
q.put()
向消息队列中存放一条消息,当消息队列满的时候,会阻塞存放的消息类型可以是数字列表,字符串等.
q.full() 判断消息队列是否已满,如果是返回True,否则返回false.
q.qsize()
查看当前队列中的消息数量
q.get()
获取消息,每次获取一条,当消息队列为空时,则阻塞.
q.empty()
消息队列为空返回True 否则返回False.
put get 中block参数和timeout参数 blcok 默认为True 表示两个函数都是阻塞函数, 如果设置为False则表示不阻塞.
timeout 当block设置为True的时候表示超时等待时间.
共享内存:
在内存中开辟一段内存空间存储数据,每次存储的内容会覆盖上次的内容.由于没有对内存进行格式化的修饰所以存取速度快效率高.
from multiprocessing import Value,Array.
信号:
kill -l 查看系统信号
kill -signame PID 给进程号PID的进程发送signame信号
信号:
信号名称 含义 默认处理方法
SIGHUP
SIGINT
SIGQUIT
SIGKILL
SIGSTOP
SIGTSTP
SIGALRM
名称: 系统定义
含义: 系统定义
处理方式: 采用默认方式处理(终止,暂停,忽略)
忽略信号
采用自定义的方式处理.
如何发送信号:
os.kill(pid,sig)
功能: 向一个进程发送一个信号
参数: PID: 要发送进程的PID号
sig:要发送的信号.
signal.alarm(sec)
功能: 给自己发送一个时钟信号(SIGALRM)
参数: sec: 参数,表示在相应的的秒数后发送时钟信号.
*信号是一种异步的进程间通信方式.
*alarm函数在一个进程如果使用多次,则后面的时间会覆盖前面的时间.
信号的处理:
signal.pause()
阻塞等待信号的发生.
signal.signal(signum,handler)
功能: 处理信号
参数: signum: 表示可以处理的信号
handler:信号的处理方法
默认的处理方式: SIG_DFL
忽略信号:SIG_IGN
自定义的方式: funciton
*signal异步处理信号的函数.
*SIGSTOP SIGKILL不能被signal函数处理.
僵尸进程的信号处理方案:
signal(SIGHLD,SIG_IGN)
同步和互斥:
临界资源: 对多个进程或者线程都可见的资源,容易产生争夺,我们将这类资源称为临界资源.
临界区: 对临界资源进行操作的代码区称之为临界区
解决资源争夺: 同步 或者 互斥.
同步: 同步是一种合作关系,为完成某种任务而建立的多个进程或者线程之间的协调调用,持续等待,传递消息告知资源占用情况.
互斥: 互斥是一种制约关系,当一个进程或者线程进入到临界区后会进行枷锁操作,此时其他进程(线程)无法进入临界区, 只有改进程(线程)使用后进程解锁,其他人才可以使用.这种技术往往是通过阻塞完成的.
Event 事件
event函数