zoukankan      html  css  js  c++  java
  • Process用法与进程详解

    僵尸与孤儿进程

    僵尸进程:父进程的子进程结束的时候父进程没有wait()情况下子进程会变成僵尸进程

    孤儿进程(无害)
    一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

    情况1 无害
    父进等着子进程都死,回收僵尸进程。

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

    情况3 有害
    父进程一直不死,造成了大量僵尸进程。占用了大量的pid号

    pid号是有限的。
    解决方案:
    最直接的办法就是杀死父进程 。

    Process用法

    之前我们简单介绍了如何用Process实现简单的多线程

    join的用法

    join 的作用主要是阻塞住主进程再等待子进程结束,然后再往下执行,(了解的是:内部会待用wait())

    join的写法和start类似,一般用于start之后

    from multiprocessing import Process
    import time
    def foo():
        print('进程  start ')
        time.sleep(2.3)
        print('进程  end ')
    
    
    
    if __name__ == '__main__':
        p = Process(target=foo)
        p.start() #
        # 核心需求就是
        # time.sleep(5)
        p.join() # 阻塞住主进程再等待子进程结束,然后再往下执行,(了解的是:内部会待用wait())
        print('主')
    

    join的多进程用法

    如果不止一个进程的话,join又会被如何使用呢

    from multiprocessing import Process
    import time
    def foo(x):
        print('进程  start ')
        time.sleep(x)
        print('进程  end ')
    
    
    
    if __name__ == '__main__':
        p1 = Process(target=foo,args=(1,))
        p2 = Process(target=foo,args=(2,))
        p3 = Process(target=foo,args=(3,))
        start = time.time()
        p1.start() #
        p2.start() #
        p3.start() #
        # 核心需求就是
        # time.sleep(5)
        p3.join() #1s
        p1.join() #1s
        p2.join() #1s
        # 总时长:按照最长的时间计算多一点。
        end = time.time()
        print(end-start) #3s多 or 6s多  ?  正解:3s多
        print('主')
    

    在这种用法中,我们使用了三个进程。我们先将三个进程都启动,随后再同时join。我们会发现最后的结果是3秒多一点。其实这三个进程是同时开始的,当第一个进程结束的时候,第二个和第三个进程已经开始一秒多了,所以最后的结果是3秒多

    当然,如果我们一个一个的start然后join也是可以达成串行的结果:

    from multiprocessing import Process
    import time
    def foo(x):
        print(f'进程{x}  start ')
        time.sleep(x)
        print(f'进程{x}  end ')
    
    
    
    if __name__ == '__main__':
        p1 = Process(target=foo,args=(1,))
        p2 = Process(target=foo,args=(2,))
        p3 = Process(target=foo,args=(3,))
        start = time.time()
        p1.start() #
        p1.join() #
        p2.start() #
        p2.join() #
        p3.start() #
        p3.join() #
        # 不如不开,直接穿行调用函数反而快
        # foo(1)
        # foo(2)
        # foo(3)
        end = time.time()
        print(end-start) 
        print('主')
    

    只不过这样的总时长反而高于串行,而且代码冗余,没有什么意义

    join的多线程用法优化

    不知道各位看官有没有觉得之前的进程每个都要写一个start和join,看上去很麻烦吗?如果三个进程还可以接受,那如果更多的进程呢?我们可以依次利用循环对其进行优化

    from multiprocessing import Process
    import time
    def foo(x):
        print(f'进程{x}  start ')
        time.sleep(x)
        print(f'进程{x}  end ')
    
    
    
    if __name__ == '__main__':
        start = time.time()
        p_list = []
        for i in range(1,4):
            p = Process(target=foo,args=(i,))
            p.start()
            p_list.append(p)
        print(p_list)
        for p in p_list:
            p.join()
        end = time.time()
        print(end-start) #3s多 or 6s多  ?  正解:3s多
        print('主')
    

    这样子代码的效果 是一样的,但是看上去就更加的简单美观了

    Process其他用法

    pid(),getpid()和getppid()

    其他比较常见的用法是pid(),getpid()和getppid(),他们可以分别用在子进程和父进程中。我们可以直接用代码来表示用法

    from multiprocessing import Process,current_process
    import time,os
    
    def task():
    
        print('子进程 start')
        print('在子进程中查看自己的pid',current_process().pid) # 在子进程中查看自己的pid
        print('在子进程中查看父进程的pid',os.getppid()) #
        time.sleep(200)
        print('子进程 end')
    
    if __name__ == '__main__':
    
        p = Process(target=task)
        p.start()
        print('在主进程查看子进程的pid',p.pid) # 一定要写在 start()之后
        print('主进程的pid',os.getpid())
        print('主进程的父进程pid',os.getppid())
        print('主')
    

    这些用法都是站在当前进程的角度
    os.getpid():获取当前进程的pid
    os.getppid():获取当前进程的父进程的pid
    子进程对象.pid:获取当前进程的子进程pid

    name和is_alive

    p.name:进程的名称

    p.is_alive():如果p仍然运行,返回True,没有运行则返回False

    from multiprocessing import Process,current_process
    import time
    def foo():
        print('进程 start')
        # print('---------------------    ',current_process().name)
        time.sleep(2)
        print('进程 end')
    
    
    if __name__ == '__main__':
        p = Process(target=foo)
        # p2 = Process(target=foo,name='rocky')
    
        p.start()
        # p2.start()
        print(p.is_alive()) # True
        time.sleep(5)
        print(p.is_alive()) # 代码运行完了就算死了 False
        print(p.name)
        # print(p2.name)
        print('主')
    

    terminate()

    p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁

    from multiprocessing import Process,current_process
    import time
    def foo():
        print('进程 start')
        # print('---------------------    ',current_process().name)
        time.sleep(4294967)
        print('进程 end')
    
    
    if __name__ == '__main__':
        p = Process(target=foo)
    
    
        p.start()
        p.terminate() # 给操作系统发了一个请求
        print(p.is_alive()) # True
        p.join()
        print(p.is_alive()) # False
    
        print('主')
    

    如上述代码,在使用terminate之后程序并不会睡4294967(sleep所能睡的最大的值,不要问我是怎么知道的),而是会直接结束,当然foo()函数里的所有代码都不会运行,当然,如果你在terminate之前sleep一下的话,那么在执行terminate之前的foo()里的代码还是会运行的

    守护进程

    守护--》伴随
    本质也是一个子进程
    主进程的代码执行完毕守护进程直接结束。但是此时主进程可能没有结束.

    from multiprocessing import Process
    import time
    def foo():
        print('守护进程 start')
        time.sleep(5)
        print('守护进程 end')
    
    
    
    if __name__ == '__main__':
        p = Process(target=foo)
        p.daemon = True # 把这个子进程定义为了守护进程
        p.start()
        time.sleep(2)
        print('主')
    

    守护进程在主进程结束后也会直接结束,上述代码中 守护进程 end 并不会被执行

    from multiprocessing import Process
    import time
    def foo():
        print('守护进程 start')
        time.sleep(3)
        print('守护进程 end')
    
    def task():
        print('子进程 start')
        time.sleep(5)
        print('子进程 end')
    
    
    if __name__ == '__main__':
        p = Process(target=foo)
        p2 = Process(target=task)
        p.daemon = True # 把这个子进程定义为了守护进程
        p.start()
        p2.start()
        time.sleep(1)
        print('主')
    

    而子进程则不一样,他并不会随着主进程结束而结束,所以它会变成孤儿进程

  • 相关阅读:
    WAP协议研究笔记—彩信的传输
    应用程序重起自身等几则技巧
    谁妨碍了我们快乐
    国庆长假总结
    关于输入法的两个问题
    反刍
    为什么,一个思维方式的问题,一个习惯的问题,已经意识到了这一点,
    电影池子,
    幻想下,
    意识流,
  • 原文地址:https://www.cnblogs.com/hyc123/p/11528091.html
Copyright © 2011-2022 走看看