10月26日开启进程以及扩展点

发布时间 2023-10-26 11:19:13作者: songjunwan

开启进程

开启子进程的时候:把父进程的代码完整复制到一个新的内存空间里去执行,达到多个并行的作用

开启方式一

首先调用multiprocessing里面的Process

from multiprocessing import Process

先搞个基本的框架


from multiprocessing import Process#导入这个模块来进行开启子进程

import time#这里导入时间模块来方便下面的代码进行分析

def task():
    print('开启进程')
    time.sleep(2)
    print('进程结束')


if __name__ == '__main__':#这里有一个坑,通常的执行情况是先开启子进程在启动父进程,但是这里是父进程先启动子进程在启动
    p = Process(target=task)  # 这里实例化Process,做好开进程的准备
    p.start()  # 这一步是告诉操作系统要开子进程,告诉完了这行代码就算执行完了,接着往下走,具体操作系统什么时候开启子进程是操作系统决定的,这个时间段它会执行下面的代码
    print('父进程')

这里面的全局调用必须要有,然后这全局调用里面有个一坑,就是通常的情况下通常的执行情况是先开启子进程在启动父进程,但是这里是父进程先启动子进程在启动,具体原因是p.start()这个代码它是告诉操作系统开启子进程,具体开启时间是由操作系统决定的,然后这个时间内是可以进行下面的操作的,所以会出现这个情况

比如我的电脑才启动的时候我开启qq,双击是我给操作系统来发送请求,然后开启是要操作系统来开启,这个等待时间如果比较长我就可以打开其它的软件(程序=代码)

开启多个子进程只用添加一下即可


from multiprocessing import Process#导入这个模块来进行开启子进程

import time#这里导入时间模块来方便下面的代码进行分析

def task(x):
    print(f'开启进程{x}')
    time.sleep(2)
    print(f'进程结束{x}')



if __name__ == '__main__':#这里有一个坑,通常的执行情况是先开启子进程在启动父进程,但是这里是父进程先启动子进程在启动
    p = Process(target=task,args=('rocky',))  # 这里实例化Process,做好开进程的准备,然后里面的target是将需要开启子进程的函数传进去,args是给函数里面传参,要以元组的形式
    p2 = Process(target=task,args=('nick',))
    p.start()  # 这一步是告诉操作系统要开子进程,告诉完了这行代码就算执行完了,接着往下走,具体操作系统什么时候开启子进程是操作系统决定的,这个时间段它会执行下面的代码
    p2.start()
    # time.sleep(5)
    print('父进程')

这个代码里面我给函数变成了有参函数可以给内部传参,为什么要这么做是因为和其它的子进程容易区分开,下面当我要开启子进程时给操作系统发信息时,就需要在Process里面多添加一个args=(要传入元组同时要有逗号)。

这里详细讲一下Process这个方法它的第一个target=是将要开启子进程的函数赋值给target这个固定格式,第二个args=()就是给括号里面传元组同时传完元组就要用逗号否则会报错

结果如下

开启方式二

开启方式和第二个差不多,这个就是如何给类开启子进程具体代码如下

from multiprocessing import Process
import time


class Test(Process):
    def __init__(self, sex):  # 这个看起来是__init__方法,但实际上这个是自己定义的__init__方法
        super().__init__()  # 这里用super的特殊性去查找这个方法调用,如果不使用super会出现报错的,因为这个是直接定义的__init__方法
        self.sex = sex

    def run(self):
        print(f'子进程{self.sex}开始了')
        time.sleep(2)#让这个结束和开始间隔两秒
        print(f'子进程{self.sex}结束了')


if __name__ == '__main__':
    p = Test('菌菇')#给这个子进程赋个名字
    p.start()  # 向操作系统发送开启子进程的请求
    print('主进程')#这里也是验证开启子进程方式一的情况

方式一就是给函数开启多个进程,而方式二就是给类来开启多个进程

开启多个进程的方法就是多生成一个子进程实例对象就可以了,具体如下

from multiprocessing import Process
import time


class Test(Process):
    def __init__(self, sex):  # 这个看起来是__init__方法,但实际上这个是自己定义的__init__方法
        super().__init__()  # 这里用super的特殊性去查找这个方法调用,如果不使用super会出现报错的,因为这个是直接定义的__init__方法
        self.sex = sex

    def run(self):
        print(f'子进程{self.sex}开始了')
        time.sleep(2)#让这个结束和开始间隔两秒
        print(f'子进程{self.sex}结束了')


if __name__ == '__main__':
    p = Test('菌菇君')#给这个子进程赋个名字
    p.start()  # 向操作系统发送开启子进程的请求
    #这里添加多个子进程实例对象来使用
    p2 = Test('暴君')
    p2.start()
    p3 = Test('主宰')
    p3.start()
    print('主进程')#这里也是验证开启子进程方式一的情况

结果如图

验证主进程和子进程直接是否具有内存隔离

验证代码如下

import time  # 导入time模块来让主进程进行睡眠
from multiprocessing import Process

x = 0  # 这就是主进程里面的x


def task():
    global x
    x = 100
    print(f'子进程的x修改为了{x}')


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    time.sleep(5)  # 这里让主进程睡眠5秒后再运行
    print(x)  # 这里来输出主进程里面的x

具体如何验证的呢?

先设计一个变量x(这是主进程里的),然后这设计一个函数在里面声明它的x是全局的x但是我让它以子进程的方式来启动。

结果如下

结果就说明了主进程和子进程之间存在内存隔离

僵尸进程以及孤儿进程(了解)

首先思考一个问题主进程运行完了是不是要等子进程运行完了才结束?

首先看一个代码


from multiprocessing import Process
import time


class Test(Process):
    def __init__(self, sex):  # 这个看起来是__init__方法,但实际上这个是自己定义的__init__方法
        super().__init__()  # 这里用super的特殊性去查找这个方法调用,如果不使用super会出现报错的,因为这个是直接定义的__init__方法
        self.sex = sex

    def run(self):
        print(f'子进程{self.sex}开始了')
        time.sleep(2)#让这个结束和开始间隔两秒
        print(f'子进程{self.sex}结束了')


if __name__ == '__main__':
    print('主进程')#这里也是验证开启子进程方式一的情况
    time.sleep(5)
    p = Test('菌菇君')#给这个子进程赋个名字
    p.start()  # 向操作系统发送开启子进程的请求
    #这里添加多个子进程实例对象来使用
    p2 = Test('暴君')
    p2.start()
    p3 = Test('主宰')
    p3.start()

这里我用time模块的方法让子进程等主进程运行,它在运行

结果如图

结果图就说明了这一点主进程结束了,还在等子进程结束,为什么会这样呢?

这就要说到僵尸进程了,僵尸进程就是子进程终止后,父进程未回收子进程相关的资源(pid也就是进程标识符)这种情况就会造成子进程结束了但是它依旧占着这个pid的值,(pid值是有限的)

pid这个是操作系统分配给每个运行中的进程唯一值,pid有些类似身份证。

僵尸进程可以这么想:有个人去世了,他的身份证没有去注销,此时在身份证管理系统里还是有他的位置,如果不销毁这个资源就会被占用着。

所以才会有主进程等待子进程结束

孤儿进程

就是没有父进程了,这么理解就是子进程在运行时,父进程因为一些缘故突然结束了,然后子进程还在运行,这时候子进程就没有父进程来管了就成了孤儿进程,但是会有init进程给收回的

总结一下僵尸进程是有害的,孤儿进程是无害的

"""
情况1:无害
父进程等着子进程都运行完后,才结束


情况2:无害
父进程死了,子进程活着,都要被init进程接管并且回收

情况3:有害
父进程一直没有结束,造成了大量的僵尸进程,占用了大量的pid号
pid号是有限的
解决方案:
直接让父进程停止
"""