开启子进程的方式1
from multiprocessing import Process
import time
def task():
print('进程 start')
time.sleep(2)
print('进程 end')
if __name__ == '__main__':#当开启子进程的时候,执行main内的代码
# 不会出现像递归一样的方式,一直创建子进程,在main内只会创建一个子进程
p = Process(target=task)#开子进程 申请新的内存空间 把父进程的所有代码完整拷贝一份过去
p.start()#告诉操作系统要开启子进程
time.sleep(3)
print('主进程')
###############
进程 start
进程 end
主进程
方式1开启多个子进程
from multiprocessing import Process
import time
def task(x):
print(f'子进程{x}-————>start')
time.sleep(2)
print(f'进程{x}-————>end')
if __name__ == '__main__':#当开启子进程的时候,执行main内的代码
# 不会出现像递归一样的方式,一直创建子进程,在main内只会创建一个子进程
p1 = Process(target=task,args=('ocean',))#开子进程 申请新的内存空间 把父进程的所有代码完整拷贝一份过去
p2 = Process(target=task,args=('sky',))
p1.start()
p2.start()
time.sleep(2)
print('主进程')
#################
子进程ocean-————>start
子进程sky-————>start
主进程
进程ocean-————>end
进程sky-————>end
开启子进程的方式2
from multiprocessing import Process
import time
class Test(Process):
def __init__(self,sex):
super().__init__()
self.sex = sex
def run(self):
print(f'子进程的性别是{self.sex}------>start')
time.sleep(1)
print(f'子进程end')
if __name__ == '__main__':#当开启子进程的时候,执行main内的代码
# 不会出现像递归一样的方式,一直创建子进程,在main内只会创建一个子进程
p = Test('女')#开子进程 申请新的内存空间 把父进程的所有代码完整拷贝一份过去
p.start()
print('主进程')
##############################
主进程
子进程的性别是女------>start
子进程end
验证隔离性(内存空间隔离)
from multiprocessing import Process
import time
x = 0
def task():
global x
x = 100
print('子进程的x修改为{}'.format(x))
if __name__ == '__main__':
p = Process(target=task)
p.start()
time.sleep(3)
print(x)
#################
子进程的x修改为100
0
僵尸进程和孤儿进程
- 僵尸进程:父进程的子进程结束的时候父进程没有wait()情况下子进程会变成僵尸进程。父进程等着所有的子进程结束才会结束。
- 孤儿进程(无害)一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
- 有害的情况
- 情况1 无害父进等着子进程都死,回收僵尸进程。
2. 情况2 无害父进程死了,子进程活着,都要被init进程接管并且回收。
3. 情况3父进程一直不死,造成了大量僵尸进程。占用了大量的pid号pid号是有限的。
4. 解决方案:最直接的办法就是杀死父进程 。
- 情况1 无害父进等着子进程都死,回收僵尸进程。
进程的创建
但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。
而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程:
- 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
- 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
- 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
- 一个批处理作业的初始化(只在大型机的批处理系统中应用)
无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。
1.1 UNIX和Windows创建进程
- 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
- 在Windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
关于创建子进程,UNIX和Windows:
- 相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。
- 不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于Windows系统来说,从一开始父进程与子进程的地址空间就是不同的。
进程的结束
- 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
- 出错退出(自愿,python a.py中a.py不存在)
- 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
- 被其他进程杀死(非自愿,如kill -9)