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('主')
    

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

  • 相关阅读:
    Leetcode Plus One
    Leetcode Swap Nodes in Pairs
    Leetcode Remove Nth Node From End of List
    leetcode Remove Duplicates from Sorted Array
    leetcode Remove Element
    leetcode Container With Most Water
    leetcode String to Integer (atoi)
    leetcode Palindrome Number
    leetcode Roman to Integer
    leetcode ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/hyc123/p/11528091.html
Copyright © 2011-2022 走看看