• 并发编程 ~~~ 多进程~~~守护进程, 僵尸进程与孤儿进程, 互斥锁, 进程之间的通信, 生产者消费者模型


    一 守护进程

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

    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  # 在进程start之前,将p子进程设置成守护进程,只要主进程结束,守护进程马上结束.
        p.start()
        time.sleep(1)
        print('主进程')
    

    二 僵尸进程与孤儿进程

    基于Unix环境(linux, macOS)

    1. 主进程需要等子进程结束之后才结束

      主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内将子进程进行回收.

    2. 为什么主进程不会在子进程结束后马上对其回收?

      主进程与子进程是异步关系,主进程无法马上捕获子进程什么时候结束.

      如果子进程结束之后马上在内存中释放资源,主进程就没有办法监测子进程的状态了

    3. unix针对上面问题提供了一个机制:

      所有的子进程结束之后,立马会释放掉文件的操作链接,内存的大部分数据,但是会保留一些内容:进程号,结束时间,运行状态,等待主进程监测,回收.

    4. 僵尸进程:所有的子进程结束之后,在被主进程回收之前,都会进入僵尸进程状态.

      危害: 如果主进程不对僵尸进程回收(wait/waitpid),产生大量的僵尸进程,这样就会占用内存,占用进程pid号.

      解决: 直接杀死主进程,将所有的僵尸进程变成孤儿进程,由init进行回收.

    5. 孤儿进程: 主进程由于某种原因结束了,但是子进程还在运行,这些子进程就变成了孤儿进程.主进程结束了,所有的孤儿进程就会被init进行回收,init就变成了主进程,将其进行回收.

    三 互斥锁

    from multiprocessing import Process
    import time
    import random
    import os
    import json
    from  multiprocessing import Lock
    def task(lock):
        lock.acquire()
        print(f'{os.getpid()}开始打印')
        time.sleep(random.randint(1,3))
        print(f'{os.getpid()}打印结束')
        lock.release()
    
    if __name__ == '__main__':
        lock = Lock()
        for i in range(3):
            p = Process(target=task,args=(lock,))
            p.start()
    

    当很多进程共抢一个资源(数据)时,要保证其顺序进行(数据的安全),这时要给它加一把锁,使其串行,这把锁就叫互斥锁.
    互斥锁: 可以公平性的保证顺序以及数据的安全.

    lock 和 join 的区别

    共同点: 都可以把并发变成串行,保证了程序有顺进行

    不同点: join 人为设定顺序,lock 让其争抢顺序,保证了公平性.

    四 进程之间的通信

    1. 基于文件通信:

    进程在内存级别是隔离的,但是文件在磁盘上,可以对其访问

    from multiprocessing import Process
    import time
    import random
    import os
    import json
    from  multiprocessing import Lock
    def search():
        time.sleep(random.randint(1,3))
        with open('t1.json',encoding='utf-8')as f:
            dic = json.load(f)
            print(f'{os.getpid()}查看了票数,还剩{dic["count"]}张票')
    
    def buy():
        with open('t1.json', encoding='utf-8')as f:
            dic = json.load(f)
        if dic["count"] > 0:
            dic['count'] -= 1
            time.sleep(random.randint(1, 3))
            with open('t1.json','w',encoding='utf-8')as f1:
                json.dump(dic,f1)
            print(f'{os.getpid()}购票成功')
        else:
            print('没票了')
    
    def task(lock):
        search()
        lock.acquire()
        buy()
        lock.release()
    
    if __name__ == '__main__':
        lock = Lock()
        for i in range(6):
            p = Process(target=task,args=(lock,))
            p.start()
    

    基于文件的进程之间的通信: 效率低, 自己加锁而且容易出现死锁.

    2. 基于队列通信

    队列的特性: 先进先出(FIFO),永远保持这个数据.

    from multiprocessing import Queue
    q = Queue(3) # maxsize 最大容量
    
    q.put(1)
    q.put('asdr')
    q.put([1,2,3])
    q.put(666,block=False) # 不写block默认为True,超过最大容量会阻塞,block = False直接报错
    q.put(666,timeout=3) # 延迟3s之后还阻塞直接报错
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get(block=False))
    print(q.get(timeout=3))
    

    五 生产者消费者模型

    生产者消费者模型三要素:

    生产者: 产生数据

    消费者: 接收数据做进一步处理

    容器: 队列

    队列容器的作用: 起到缓冲的作用,平衡生产力与消费力,解耦

    from multiprocessing import Process,Queue
    import time,random
    
    def producer(q,name):
        for i in range(1,6):
            time.sleep(random.randint(1,2))
            res = f'{i}号包子'
            q.put(res)
            print(f'生产者{name}生产了{res}')
    
    def consumer(q,name):
        while 1:
            try:
                food = q.get(timeout=3)
                time.sleep(random.randint(1,3))
                print(f'消费者{name}吃了{food}')
            except Exception:
                return
    
    if __name__ == '__main__':
        q = Queue()
        p1 = Process(target=producer,args=(q,'孙宇'))
        p2 = Process(target=consumer,args=(q,'海狗'))
    
        p1.start()
        p2.start()
    
  • 相关阅读:
    MATLAB 2019a 安装包及安装教程
    三角形最大周长
    两数的和
    “精致”的数
    总分最高的学生姓名和各科成绩
    列表元素改写
    统计单词个数
    凯撒密码
    Django入门学习--配置路由(urls)
    Django入门学习--熟悉配置信息
  • 原文地址:https://www.cnblogs.com/lav3nder/p/11802258.html
Copyright © 2020-2023  润新知