• 并发编程(2)


    1. 孤儿进程

    '''
    孤儿进程(无害)
        一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作
    
    
    情况1: 父进程正常回收子进程 (无害)
        父进程等着子进程都死,回收僵尸进程
        
    情况2:父进程先死了,出现了孤儿进程 (无害)
        父进程死了,子进程活着,都要被init进程接管并且回收
    
    情况3:父进程一直不死不断开启子进程,并且不手动回收 (有害)
        父进程一直不死不断开启子进程,父进程不死,init不会帮父进程回收,造成了大量僵尸进程。占用了大量的pid号
        
    pid号是有限的
    情况3解决方案:
        最直接的办法就是杀死父进程,所有的子进程均变为子进程均变为孤儿进程,统一由init回收
    '''
    

    2. join用法

    # 用法一:
    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('主')
    
    # 用法二:
    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()
        # 换顺序也是按照时长最长的那个计算
        p1.join()
        p2.join()
        p3.join()
        # 总时长:按照最长的时间计算多一点
        end = time.time()
        print(end-start)
        print('主')
    
    
    # 用法三(jon串行):
    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()
        # 不如不开进程,直接串行调用函数反而快
        # 总时长:所有的时间加在一起多一点
        end = time.time()
        print(end - start)
        print('主')
    
    # 用法四(优化用法二):
    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)  # 总时长:按照最长的时间计算多一点
        print('主')
    

    3. Process的其他小用法

    # pid 和 ppid 的用法
    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(5)
        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('主')
    
    '''
    掌握pid 和 ppid 的查看方式:
    # 角度 站在当前进程的角度
    os.getpid() / current_process().pid # 获取当前进程的pid
    os.getppid() # 获取当前进程的父进程的pid
    子进程对象.pid # 获取当前进程的子进程
    '''
    
    
    # name的用法
    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)
        p3 = Process(target=foo,name = 'ys')
        p.start()
        p2.start()
        p3.start()
        print(p.name)
        print(p2.name)
        print(p3.name)
        print('主')
    
    
    # is_alive的用法
    from multiprocessing import Process,current_process
    import time
    
    def foo():
        print('进程 start')
        time.sleep(2)
        print('进程 end')
    
    if __name__ == '__main__':
        p = Process(target=foo)
        p.start()
        print(p.is_alive())  # True 判断子进程代码是否结束
        time.sleep(5)
        print(p.is_alive())  # 代码运行完了就算死了  False
        print('主')
        
    
    # terminal的用法
    from multiprocessing import Process
    import time
    
    def foo():
        print('进程 start')
        time.sleep(50)
        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('主')
    

    4. 守护程序

    '''
    守护进程
        守护进程会在主进程代码执行结束后就终止
        守护进程内无法再开启子进程,否则抛出异常
    守护---》伴随
    本质也是一个子进程
    主进程的代码执行完毕守护进程直接结束,但是此时主进程可能没有结束
    当主进程代码结束,该子进程再执行无意义的情况可以用守护进程
    '''
    
    # 主进程代码运行完,守护进程立即结束
    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  # 把这个子进程定义为了守护进程,一定要在start之前
        p.start()
        time.sleep(2)
        print('主')
    
    # 守护进程一旦发现主进程代码运行完,立刻结束,并不会管自己的进程是否运行完
    
    # # 主进程代码运行完后等在子进程运行阶段,线程不会参与守护
    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('主')
    
    # 守护进程在运行完主进程最后一行代码就结束,但是主进程并没有结束,主进程在等待子进程运行结束.
    

    5. 抢票小程序

    from multiprocessing import Process
    import json,time,os
    
    def search():
        time.sleep(1)  # 模拟网络io
        with open('db','rt',encoding='utf-8') as f:
            res = json.load(f)
            print(f'还剩{res["count"]}')
    
    def get():
        with open('db','rt',encoding='utf-8') as f:
            res = json.load(f)
        time.sleep(1) # 模拟网络io
        if res['count'] > 0:
            res['count'] -= 1
            with open('db','wt',encoding='utf-8') as f:
                json.dump(res,f)
                print(f'进程{os.getpid()}抢票成功')
            time.sleep(1.5)  # 模拟io
        else:
            print('票已售空!!!')
    
    def task():
        search()
        get()
    
    if __name__ == '__main__':
        for i in range(15):
            p = Process(target=task)
            p.start()
            p.join()
    
    # 为了保证数据的安全,要牺牲掉效率
    
  • 相关阅读:
    Java LinkedHashMap 逆序遍历
    (java/javascript) list 交集 并集 差集 去重复并集
    Map集合的四种遍历方式(转载)
    本地jar包 安装到本地仓库中的命令
    BigDecimal加减乘除运算(转)
    反射与内置方法
    项目二:选课系统
    绑定方法与非绑定方法
    多态性与鸭子类型
    继承与派生
  • 原文地址:https://www.cnblogs.com/yushan1/p/11515189.html
Copyright © 2020-2023  润新知