python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程

python并发编程02 /多进程、进程的创建、进程PID、join方法、进程对象属性、守护进程

1. 进程创建的两种方式

  • 开启进程的第一种方式

    from multiProcessing import Process
    import time
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is gone')
        
    if __name__ == '__main__':
        p = Process(target=task,args=('张三',))   # 创建一个进程对象
        p.start()
        print('==主开始')
      
        
    # 1.在window环境下,开启进程必须__name=='__main__'下面
    #   原因:这是 Windows 上多进程的实现问题。在 Windows 上,子进程会自动 import 启动它的这个文件,而在 import 的时候是会执行这些语句的。如果你这么写的话就会无限递归创建子进程报错。所以必须把创建子进程的部分用那个 if 判断保护起来,import 的时候 __name__ 不是 __main__ ,就不会递归运行了。
    
    # 2.p.start()
    #   只是向操作系统发出一个开辟子进程的信号,然后就执行下一行了,这个信号操作系统接收到之后,会从内存中开辟子进程空间,然后再将主进程所有数据copy加载到子进程,然后再调用CPU去执行.
    
    # 3.开辟子进程开销是很大的,所以永远会先执行主进程的代码
    
  • 开启进程的第二种方式

    from multiprocessing import Process
    import time
    
    class MyProcess(Process):
    
        def __init__(self,name):
            super().__init__()
            self.name = name
    
        def run(self):
            print(f'{self.name} is running')
            time.sleep(2)
            print(f'{self.name} is gone')
    
    
    if __name__ == '__main__':
        p = MyProcess('张三')
        p.start()
        print('===主')
    
  • 简单应用

    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(1)
        print(f'{name} is gone')
    
    def task1(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is gone')
    
    def task2(name):
        print(f'{name} is running')
        time.sleep(3)
        print(f'{name} is gone')
    
    
    if __name__ == '__main__':
        # 一个进程串行的执行三个任务
        start_time = time.time()
        task('张三')
        task1('李四')
        task2('王五')
        print(f'结束时间{time.time() - start_time}')
        
        # 三个进程 并发或者并行的执行三个任务
        start_time = time.time()
        p1 = Process(target=task, args=('李四',))   # 创建一个进程对象
        p2 = Process(target=task1, args=('王五',))  # 创建一个进程对象
        p1.start()
        p2.start()
        task2('张三')
        print(f'结束时间{time.time()-start_time}')
    

2. 进程PID

  • pid是进程在内存中的唯一标识

  • pid的获取:

    命令行获取所有的进程的pid:tasklist;命令行获取某个进程的pid:tasklist|findstr python

    代码级别获取一个进程的pid

    import os
    print(os.getpid())
    

    获取父进程(主进程)的pid

    import os
    print(f'子进程:{os.getpid()}')
    print(f'主(父)进程:{os.getppid(())}')
    
  • 验证进程之间的空间隔离

    from multiprocessing import Process
    import time
    name = '张三'
    
    def task():
        global name
        name = '李四'
        print(f'子进程{name}')
    
    
    if __name__ == '__main__':
        p = Process(target=task)  # 创建一个进程对象
        p.start()
        # print('==主开始')
        time.sleep(3)
        print(f'主:{name}')
        
    # 不能共享内存的数据
    

3. 进程对象join方法

  • join让主进程等待子进程结束后,再执行主进程(lock,队列)

  • 示例一:简单使用

    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
    
        p = Process(target=task,args=('太阳',))  # 创建一个进程对象
        p.start()
        p.join()
        print('==主开始')
    
  • 示例二:多个子进程使用join

    # 未使用join耗时
    from multiprocessing import Process
    import time
    
    def task(name,sec):
        print(f'{name}is running')
        time.sleep(sec)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        start_time = time.time()
        p1 = Process(target=task,args=('太阳',1))
        p2 = Process(target=task,args=('月亮',2))
        p3 = Process(target=task,args=('星星',3))
        p1.start()
        p2.start()
        p3.start()
        print(f'==主{time.time()-start_time}')  # 0.02 这只是主进程结束的时间,与其他进程毫无关系
        
    # 验证1:使用join,测试多个join之后的结果以及耗时
    from multiprocessing import Process
    import time
    
    def task(name,sec):
        print(f'{name}is running')
        time.sleep(sec)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        start_time = time.time()
        p1 = Process(target=task,args=('张三',1))
        p2 = Process(target=task,args=('李四',2))
        p3 = Process(target=task,args=('王五',3))
        p1.start()
        p2.start()
        p3.start()
        p1.join()
        p2.join()
        p3.join()
        print(f'==主{time.time()-start_time}')
    
    # 结果:
    张三is running
    李四is running
    王五is running
    张三 is gone
    李四 is gone
    王五 is gone
    ==主3.2888922691345215
    
    # 验证2:使用join,测试多个join之后的结果以及每个join之后的耗时
    from multiprocessing import Process
    import time
    
    def task(name,sec):
        print(f'{name}is running')
        time.sleep(sec)
        print(f'{name} is gone')
    
    
    if __name__ == '__main__':
        start_time = time.time()
        p1 = Process(target=task,args=('张三',3))
        p2 = Process(target=task,args=('李四',2))
        p3 = Process(target=task,args=('王五',1))
    
        p1.start()
        p2.start()
        p3.start()
        p1.join()
        print(f'==主1:{time.time()-start_time}')
        p2.join()
        print(f'==主2:{time.time()-start_time}')
        p3.join()
        print(f'==主3:{time.time()-start_time}') 
        
    # 结果:
    张三is running
    李四is running
    王五is running
    张三 is gone
    李四 is gone
    王五 is gone
    ==主1:3.2728402614593506
    ==主2:3.2728402614593506
    ==主3:3.2728402614593506
    
  • 优化使用多个join方法时的注意事项

    # 优化此方法
    from multiprocessing import Process
    import time
    
    def task(sec):
        print(f'is running')
        time.sleep(sec)
        print(f' is gone')
    
    if __name__ == '__main__':
        start_time = time.time()
        p1 = Process(target=task,args=(1,))
        p2 = Process(target=task,args=(2,))
        p3 = Process(target=task,args=(3,))    
        p1.start()
        p2.start()
        p3.start()    
        p1.join()
        p2.join()
        p3.join()
        
        # 错误示范:这样就是串行,一个执行完执行下一个
        for i in range(1,4):
            p = Process(target=task,args=(i,))
            p.start()
            p.join()
        p1 = Process(target=task,args=(1,))
        p1.start()
        p1.join()
        p2 = Process(target=task,args=(2,))
        p2.start()
        p2.join()
        p3 = Process(target=task,args=(3,))
        p3.start()
        p3.join()
    
        
        # 正确示范:
        l1 = []
        for i in range(1, 4):
            p = Process(target=task,args=(i,))
            l1.append(p)
            p.start()
        
        for i in l1:
            i.join()
        
        print(f'==主{time.time()-start_time}')
    
    # join就是阻塞,主进程有join,主进程下面的代码一律不执行,直到进程执行完毕之后,再执行.
    

4. 进程对象其他属性

  • 常见属性释义:

    p.terminate() :杀死子进程

    print(p.is_alive()) :判断子进程是否存活

    p.name = '子进程2' :给子进程设置名称

  • 代码示例:terminate/is_alive/p.name

    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
         p = Process(target=task,args=('张三',),name='子进程')  # 创建一个进程对象,其中的name='子进程'是给该进程设置名字为子进程
        p.start()
        time.sleep(1)
        p.terminate()    # 杀死子进程  ***
        p.join()  # ***
        time.sleep(0.5)
        print(p.is_alive())   # 判断子进程是否存活 ***
        print(p.name)
        p.name = '子进程2'    # 给子进程设置名称
        print(p.name)
        print(p.pid)         # 查看pid
        print('==主开始')
    

5. 守护进程

  • 守护进程:子进程守护着主进程,只要主进程结束,子进程就跟着结束

  • 代码示例:

    from multiprocessing import Process
    import time
    
    def task(name):
        print(f'{name} is running')
        time.sleep(2)
        print(f'{name} is gone')
    
    if __name__ == '__main__':
        p = Process(target=task,args=('太阳',))  # 创建一个进程对象
        p.daemon = True  # 将p子进程设置成守护进程,只要主进程结束,守护进程马上结束.
        p.start()
        # p.daemon = True  # 一定要在子进程开启之前设置
        time.sleep(1)
        print('===主')
    
posted @ 2019-08-20 22:46  LBZHK  阅读(224)  评论(0编辑  收藏  举报