zoukankan      html  css  js  c++  java
  • day32:进程&进程join&守护进程deamon

    目录

    1.进程的基本概念

    2.进程初体验

    3.join:先子后主

    4.守护进程:deamon

    5.使用自定义类的方式创建进程

    6.两张和进程相关的图

    进程的基本概念

    什么是进程?

    进程就是正在运行的程序,它是操作系统中,资源分配的最小单位

    什么是资源分配?

    资源分配:分配的是cpu和内存等物理资源

    Linux中几个关于进程的指令

    ps -aux    查看进程号

    ps -aux | grep 2860   查看对应进程号的进程

    kill -9 2860   杀死进程

    pid和ppid

    获取当前进程id: os.getpid()

    获取当前进程的父进程id: os.getppid()

    并行和并发

    并发:一个cpu同一时间不停执行多个程序

    并行:多个cpu同一时间不停执行多个程序

    CPU的进程调度算法

    1.先来先服务fcfs(first come first server):先来的先执行

    2.短作业优先算法:分配的cpu多,先把短的算完

    3.时间片轮转算法:每一个任务就执行一个时间片的时间.然后就执行其他的

    4.多级反馈队列算法

    越是时间长的,cpu分配的资源越少,优先级靠后

    越是时间短的,cpu分配的资源越多

    进程初体验

    1.进程的基本使用

    在使用进程之前,需要调用Process: from multiprocessing import Process

    # (1) 进程的基本使用
    def func():
        print("1.子进程id>>{},2父进程id>>{}".format(os.getpid(),os.getppid()))
    
    # 为了解决windows 和 linux 系统的兼容问题,下面这句话必须加上,否则报错
    if __name__ == "__main__":
        # 创建子进程,返回进程对象,执行func这个任务
        p = Process(target=func)
        # 调用子进程
        p.start()

    2.创建带有参数的进程

    def func(n):
        for i in range(1,n+1):
            print("1.子进程id>>{},2父进程id>>{}".format(os.getpid(),os.getppid()))
    
    if __name__ == "__main__":
        n = 5
        #创建子进程
        p = Process(target=func,args=(n,))
        #调用子进程
        p.start()
    
        for i in range(1,n+1):
            print("*" * i)

    执行结果如下图所示

    产生如上结果的原因:因为子进程分配资源需要时间,而主进程早已经分配好资源了,不需要这个时间。所以主进程的内容先打印,子进程的内容后打印

    3.进程之间的数据彼此隔离

    count = 10
    def func():
        global count
        count += 1
        print("我是子进程count={}".format(count))
    
    if __name__ == "__main__":
        p=Process(target=func)
        p.start()
        time.sleep(1)
        print(count)

    执行结果如下图所示

    产生如上结果的原因:如下图所示,黄色部分都是子进程中的内容,子进程中有+1操作,所以子进程中的count肯定为11

    但是主进程并没有任何操作,只是单纯的打印了一下count,所以主进程中的count为10

    4.多个进程之间是异步并发

    关于主进程和子进程,你需要注意的点:

    1.多个进程之间是异步并发的程序,因为cpu的调度策略问题,不一定哪个任务先执行,哪个任务后执行.

    整体而言,主进程比子进程创建的速度要快,cpu遇到阻塞会立刻切换任务,等到阻塞态的任务变成了就绪态,cpu再回来执行

    2.主程序会默认等到所有的子程序执行结束之后,在统一关闭程序,释放资源.

    若不等待,有可能在后台存有多个未执行结束的子进程,会变成僵尸进程,不停的占用cpu,内存

    增加系统的压力,所有方便于对进程的管理,主进程默认等待子进程.

    def func(n):
        time.sleep(random.randrange(3))
        print("数字{}<=>1.子进程id>>{},2父进程id>>{}".format(n,os.getpid(),os.getppid()))
    
    if __name__ == "__main__":
        for i in range(1,11):
            Process(target=func,args=(i,)).start()
            
        print("主进程执行结束了....")
        print(os.getpid())

    执行结果如下图所示

    join:先子后主

    1.join基本语法

    def func():
        print("发送第一封邮箱,要求涨工资")
    
    
    if __name__ == "__main__":
        p = Process(target=func)
        p.start()
    
        # 必须等待子进程全部执行结束之后,在执行主进程中的代码,用join来同步子父进程.
        p.join()
        # time.sleep(1)
        print("发送第二封邮箱,涨到一个月6万")

    执行结果如下图所示

    2.join:多个子进程

    def func(i):
        time.sleep(1)
        print("发送第%s封邮箱,要求升职加薪" % (i))
    
    
    if __name__ == "__main__":
        lst = []
        for i in range(10):
            p = Process(target=func, args=(i,))
            p.start()
            lst.append(p) # 把创建的十个子进程对象方放到列表中,现在他们处于就绪态
    
        for i in lst:
            i.join() # 十个子进程对象同时join
    
        print("主进程发最后一封邮件:此致敬礼~")

    执行结果如下图所示

    请注意!!!千万不要写成如下写法:

    守护进程deamon

    1.守护进程的基本概念 

    概念:

    守护进程守护的是主进程,如果主进程中的所有代码执行完毕了,

    当前这个守护进程会被立刻杀死,立刻终止.

    语法:

    进程.daemon = True---->设置当前这个进程为守护进程

    必须写在start()调用进程之前进行设置

    2.守护进程的基本使用方法

    def func():
        print("start当前子进程")
        time.sleep(1)
        print("end当前子进程")
    
    
    if __name__ == "__main__":
        p = Process(target=func)
        p.daemon = True
        p.start()
    
        print("主进程执行结束 ... ")

    执行结果如下图所示

    3.守护进程:多个子进程

    def func1():
        count = 1
        while True:
            print("*" * count)
            time.sleep(0.5)
            count += 1
    
    
    def func2():
        print("start func2 当前子进程任务")
        time.sleep(3)
        print("end   func2 当前子进程任务")
    
    
    if __name__ == "__main__":
        p1 = Process(target=func1)
        p2 = Process(target=func2)
    
        # 设置p1这个进程对象为守护进程
        p1.daemon = True
    
        p1.start()
        p2.start()
    
        time.sleep(1)
    
        print("主进程执行结束 ... ")

    执行结果如下图所示

    4.守护进程实际用途:监控报活

    # 守护进行
    def alive():
        while True:
            print("给监控的总服务器发消息,报告自己的存活状态, i am alive~")
            time.sleep(1)
    
    
    # 执行任务
    def func():
        while True:
            try:
                time.sleep(1)
                raise RuntimeError
                print("当前5号服务器功能:对日志进行数据分析.... ")
            except:
                break
            # pass
    
    
    if __name__ == "__main__":
        # 创建2个子进程
        p1 = Process(target=alive)
        p2 = Process(target=func)
        # 设置p1为守护进程
        p1.daemon = True
    
        p1.start()
        p2.start()
    
        # 必须等到p2任务执行结束之后,在向下执行.
        p2.join()
    
        print("当前服务器状态异常 ... ")

    在一切都很正常的时候,它的运行结果是这样的

    当出现问题时,它的运行结果是这样的

    使用自定义类的方法创建进程 

    自定义进程类的要求

    自定义进程类的要求:

    (1) 必须继承Process这个父类

    (2) 所有进程执行任务的逻辑必须写在run方法里面

    基本语法

    class MyProcess(Process):
        def run(self):    
            print("1.子进程id>>{},2父进程id>>{}".format(os.getpid(),os.getppid()))
            
    if __name__ == "__main__":
        p = MyProcess()
        p.start()
        print("3.子进程id>>{},4父进程id>>{}".format(os.getpid(),os.getppid()))

    带有参数自定义类的方法

    class MyProcess(Process):
        def __init__(self,arg):
            # 手动调用一下父类的构造方法(最终实现进程的创建)
            super().__init__()
            self.arg = arg
    
        def run(self):    
            print("1.子进程id>>{},2父进程id>>{}".format(os.getpid(),os.getppid()))
            print(self.arg)
        
    if __name__ == "__main__":
        p = MyProcess("我是传进来的参数")
        p.start()
        print("3.子进程id>>{},4父进程id>>{}".format(os.getpid(),os.getppid()))

    运行结果如下图所示

    请注意:在定义类中重写__init__方法中,必须要用super调用父类的__init__方法!!!

    如果没有调用的话,会出现以下这种情况:

    我们可以查看父类的__init__方法

    所以,我们使用super直接调用父类的__init__方法

    两张和进程相关的图

      

  • 相关阅读:
    spring @Primary-在spring中的使用(十九)
    Java中lombok @Builder注解使用详解(十八)
    Spring Boot的MyBatis注解:@MapperScan和@Mapper(十七)
    js基础只是总结-语句
    js基础知识-数据类型
    启动redis服务报错Creating Server TCP listening socket *:6379: bind: Address already in use [duplicate]
    gitlab 配置SSH和ACCESS TOKEN
    https nginx配置
    Vue和React区别
    深入虚拟DOM和DOM-diff
  • 原文地址:https://www.cnblogs.com/libolun/p/13519801.html
Copyright © 2011-2022 走看看