文章目录
- 多任务编程
- 进程
- 进程的优先级
- 父子进程
- 进程相关的函数
- os.getpid()
- os.getppid()
- os._exit(status)
- sys.exit([status])
- 僵尸进程
- 处理僵尸进程的方法
- os.wait()
- os.waitpid(pid, option)
- 创建二级子进程处理
- 在父进程中使用信号处理的方法,忽略子进程发来的信号
- 孤儿进程
多任务编程
可以有效的利用计算机资源,同时执行多个任务
进程
进程就是程序在计算机中一次执行的过程
进程和程序的区别:
程序是一个静态文件的描述,不占计算机的系统资源
进程是一个动态的过程,占有CPU、内存等资源,有一定的生命周期
同一个程序的不同执行过程即为不同的进程
问题1:什么决定了进程的创建
1)用户通过应用层程序进行进程的创建申请
2)调用操作系统接口进行进程创建
3)告知系统内核创建新的进程提供给应用层使用
问题2:进程如何占有CPU
1)同一个内核同一时刻只能运行一个进程
2)多个进程对内核资源进行抢占,由操作系统内核进行分配
3)哪个进程占有计算机内核,我们称为该进程占有CPU的时间片
问题3:进程在运行过程中的形态和附带内容
1)PCB(进程控制块):在linux和unix操作系统中,进程创建后会在内存中开辟一块空间存放进程的相关信息,这个空间称之为PCB
2)PID:在操作系统中进程的唯一标识,是一个大于0的正整数,由系统自动分配
ps -aux 查看进程信息
虚拟内存:每个进程占有4G内存地址空间,这里的内存指的是虚拟内存
进程状态:
三态
就绪态: 进程具备运行条件,等待系统分配处理器以便运行
运行态:进程占有cpu处于运行状态
等待态:又称为阻塞态或者睡眠态,指进程不具备运行条件,正在等待某些条件的达成
五态
就绪态: 进程具备运行条件,等待系统分配处理器以便运行
运行态:进程占有cpu处于运行状态
等待态:又称为阻塞态或者睡眠态,指进程不具备运行条件,正在等待某些条件的达成
新建:创建一个进程的过程,直接表现为执行某个程序或者在程序中创建新的进程
终止:进程执行结束,完成回收的过程
D: 等待态,不可中断等待态
S: 等待态,可中断等待态
T: 等待态,暂停状态
R: 运行态
Z: 僵尸态
+: 前台进程
N: 低优先级的进程
<: 高优先级的进程
l: 有进程链接
s: 会话组
进程的优先级
优先级往往决定了一个进程的执行权限和占有系统资源的优先程度
top: 动态查看系统进程运行情况
linux系统中优先级范围为-20—19,其中-20优先级最高,19优先级最低,0为平均状态,用户创建进程默认优先级为0
nice: 以指定的优先级运行某一个进程
nice -9 ./while.py 以9的优先级运行程序
sudo nice --9 ./while.py 以-9的优先级运行程序
renice n PID: 修改一个正在运行的进程的优先级
renice 8 4277 将4277号进程优先级修改为8
父子进程
在系统中除了初始化进程之外,每个进程都是由父进程创建的,每个进程有一个唯一的父进程,可能有多个子进程
需求:两间不相关事情希望同时来做
# test.py文件
import time
def fun1():
time.sleep(6)
print('做完第一件事情')
def fun2():
time.sleep(4)
print('做完第二件事情')
方案一:写两个进程,分别承担不同的事情,各自执行
分析:1. 两个程序比较麻烦
2. 无法确定两个程序应该在什么时间开始运行
方案二:写一个程序,在程序中指定位置调用接口来创建新的进程
实现方法: os.fork()函数实现
fork()
功能:创建一个新的进程
参数:无
返回值:
小于0 表示进程创建失败
等于0 表示在子进程中fork的返回值为0
大于0 在父进程中fork的返回值大于0
-
fork是os模块函数,只能在linux和unix下使用
测试1:父进程中fork之前的内容,子进程同样也会复制,但是父子进程空间内容的修改不会相互影响
测试2:父子进程在执行上互不影响,理论上不一定谁先执行
测试3:子进程虽然复制父进程的空间,但也有自己独特的特性,比如自己的pid,进程控制块,进程栈等。父进程中fork的返回值即为创建的子进程的pid号
# os模块提供了大量和系统相关的功能函数接口
# os模块的使用是系统相关的,在不同的系统中可能使用方法不同
import os
import time
# 创建新的进程
pid = os.fork()
if pid < 0:
print('create process failed')
elif pid == 0:
print('pid:')
print(pid)
while True:
time.sleep(0.8)
print('This is the new process')
else:
# 父进程中pid为子进程的PID号
print('parent pid:')
print(pid)
while True:
time.sleep(1)
print('This is the parent process')
print('The process end')
需求解决:
import os
import time
# 导入test中的函数
from test import *
# 创建新的进程
pid = os.fork()
if pid < 0:
print('create process failed')
elif pid == 0:
fun1()
else:
fun2()
进程相关的函数
os.getpid()
功能:获取当前进程的PID号
import os
pid = os.fork()
if pid < 0:
print('create process failed')
elif pid == 0:
print('Child process:')
print('当前进程的PID:', os.getpid())
else:
print('Parent process')
print('pid:', pid)
os.getppid()
功能:获取当前进程父进程的PID号
os._exit(status)
功能:用来结束一个进程
参数:一个数字,表示进程的退出状态,通常0表示正常退出进程,其他数字表示非正常退出
sys.exit([status])
功能:用来结束一个进程, 如果处理了抛出的异常,则不结束进程
参数:一个数字,表示进程的退出状态,同上
还可以是一个字符串,则在进程退出时会打印这个字符串
import os
import sys
# 抛出异常进程不结束
try:
sys.exit('over')
except SystemExit as e:
print(e)
print('process over')
僵尸进程
子进程先于父进程退出,父进程没有对子进程的退出做相应的处理,此时子进程就会变为僵尸进程
影响:进程退出后,仍有部分信息残留在内存中占用空间,大量的僵尸进程会影响系统运行,所以应该尽量避免僵尸进程的产生。
处理僵尸进程的方法
- 让父进程先退出(不好控制)
- 父进程处理子进程的退出(阻塞父进程的运行)
os.wait()
功能:等待子进程退出进行处理
参数:无
返回值:返回一个包含两个元素的元组,第一个是退出的子进程的PID号,第二个是子进程的退出状态
- wait是一个阻塞函数,即进程处于等待状态,等待某种条件的达成才会继续运行
import os
import sys
from time import sleep
pid = os.fork()
if pid < 0:
print('create process failed')
elif pid == 0:
print('child process...')
sleep(2)
sys.exit(6) # 子进程退出
else:
# wait 阻塞等待子进程的退出
p, status = os.wait()
print('parent process...')
print('p, status:', p, status)
os.waitpid(pid, option)
功能:同wait, 处理子进程退出,使其不会成为僵尸
参数:
pid=-1表示等待任意子进程退出
pid大于0表示等待指定进程号的子进程退出
option=0 表示阻塞等待
option=WNOHANG 表示非阻塞状态
返回值:同wait
创建二级子进程处理
# 创建二级子进程解决僵尸进程
import os
# 创建一级子进程
pid = os.fork()
if pid < 0:
print('create process failed')
elif pid == 0:
# 创建二级子进程
p = os.fork()
if p < 0:
print('process failed')
elif p == 0:
print('做二级子进程任务')
else:
# 一级子进程退出,使二级子进程成为孤儿
os._exit(0)
else:
# 等待一级子进程退出
os.wait()
print('做父进程任务')
在父进程中使用信号处理的方法,忽略子进程发来的信号
signal(SIGCHLD, SIG_IGN)
孤儿进程
父进程先于子进程退出,此时子进程就会变为孤儿进程
影响:当一个进程变为孤儿进程,系统会自动的使用一个进程成为孤儿进程的父进程。当孤儿进程退出时,该系统进程会自动回收孤儿,使他不会成为僵尸。所以孤儿进程对系统资源没有什么影响。