• 互斥锁 僵尸进程与孤儿进程


    一:僵尸进程与孤儿进程(面试会问到)

    ​ 主进程需要等待子进程结束后,主进程才结束,主进程时刻监测子进程的运行状态,当子进程结束之后,过一段时间将子进程回收

    1.为什么主进程不在子进程结束后立马对其回收呢?

    1. 主进程与子进程是异步关系,主进程无法捕获子进程什么时候结束
    2. 如果子进程结束之后马上释放资源,主进程就无法监测子进程的状态(子进程立马死掉,不热乎了就没办法了)

    2.unix 针对上面的内容提供了一个机制

    所有子进程结束后,立马释放掉文件的操作链接,内存的大部分数据,但是会保留一个内容 :进程号、结束时间、运行状态

    3.僵尸进程

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

    4.僵尸进程有无危害

    如果父进程不对子进程进行回收,产生大量的僵尸进程,这样就会占用内存,占用进程 pid 号

    5.孤儿进程

    父进程由于某种原因结束了,但是你的子进程还在运行中,这样你的子进程就成为了孤儿进程,但是如果你的父进程结束了,你的所有孤儿进程就会被 init 进程回收,对你进行回收

    init 就是充当了生活中的孤儿院

    6.僵尸进程如何解决(直接杀死父进程)

    父进程产生大量子进程,但是不作为不回收,这样就会形成大量的僵尸进程,解决方式就是直接杀死父进程,将所有的僵尸进程变成孤儿进程,由 init 回收

    二:互斥锁(保证数据安全,自己加锁容易死锁)

    三个同事 同时用一个打印机打印内容.
    
    三个进程模拟三个同事, 输出平台模拟打印机.
    

    版本一

    存在的问题 : 现在是所有进程并发的抢占打印机,并发是以效率优先,并发是以效率优先的,但是我们现在是以顺序优先的,多个进程抢占一个资源时必须保证资源,要保证顺序优先,串行,一个一个来

    from multiprocessing import Process
    import time
    import os
    import random
    
    def task1():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1,3))
        print(f"{os.getpid()}打印结束了")
    def task2():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    def task3():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    if __name__ == '__main__':
        p1 = Process(target = task1)
        p2 = Process(target = task2)
        p3 = Process(target = task3)
    
        p1.start()
        p2.start()
        p3.start()
    """
    8067开始打印了
    8068开始打印了
    8069开始打印了
    8068打印结束了
    8067打印结束了
    8069打印结束了
    一个字概括   乱
    """
    

    **版本二 : **

    利用了 join 解决了串行问题,保证了顺序优先,但是这个谁先谁后是固定的,这样是不对的,你在争抢同一个资源时,顺序应该是不固定的……所以引出了下面的互斥锁

    from multiprocessing import Process
    import time
    import os
    import random
    
    def task1():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1,3))
        print(f"{os.getpid()}打印结束了")
    def task2():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    def task3():
        print(f"{os.getpid()}开始打印了")
        time.sleep(random.randint(1, 3))
        print(f"{os.getpid()}打印结束了")
    if __name__ == '__main__':
        p1 = Process(target = task1)
        p2 = Process(target = task2)
        p3 = Process(target = task3)
    
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    """
    9026开始打印了
    9026打印结束了
    9031开始打印了
    9031打印结束了
    9038开始打印了
    9038打印结束了
    

    lock 与 join 的区别:

    共同点 :都可以将并发变成串行,保证了执行顺序

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

    from multiprocessing import Process
    from multiprocessing import Lock
    import time
    import os
    import random
    def task1(p,lock):
        lock.acquire()
        print(f'{p}开始打印了')
        time.sleep(random.randint(1,3))
        print(f'{p}打印结束了')
        lock.release()
    
    def task2(p,lock):
        lock.acquire()
        print(f'{p}开始打印了')
        time.sleep(random.randint(1,3))
        print(f'{p}打印结束了')
        lock.release()
    
    def task3(p,lock):
        lock.acquire()
        print(f'{p}开始打印了')
        time.sleep(random.randint(1,3))
        print(f'{p}打印结束了')
        lock.release()
    
    if __name__ == '__main__':
        mutex = Lock()
        p1 = Process(target = task1,args = ('p1',mutex))
        p2 = Process(target = task1,args = ('p2',mutex))
        p3 = Process(target = task1,args = ('p3',mutex))
    
        p1.start()
        p2.start()
        p3.start()
    '''
    p1开始打印了
    p1打印结束了
    p2开始打印了
    p2打印结束了
    p3开始打印了
    p3打印结束了
    '''
    

    三:进程之间的通信

    1.基于文件通信(抢票系统)

    主要是一个操作系统

    1. 先可以查票,查询余票数 并发
    2. 进行购买,向服务端发送请求,服务端接收请求,在后端将票数减一,返回到前端
    3. 补充一个知识点,json 中,字典所有的都是双引号

    但是当多个进程共抢一个数据时,如果要保证数据的安全,必须要串行.

    要想让购买环节进行串行,加锁

    image-20190821140347311

    下面进入加锁环节

    from multiprocessing import Process
    from multiprocessing import Lock
    import time
    import os
    import random
    import json
    
    def search():
        time.sleep(random.randint(1,3))
        with open('ticket.json',mode = "r",encoding = "utf-8")as f1:
            dic = json.load(f1)
            print(f"{os.getpid()}查看了票数,剩余{dic['count']}")
    def paid():
        with open('ticket.json', encoding="utf-8")as f1:
            dic = json.load(f1)
            if dic['count'] > 0:
                dic['count'] -= 1
                time.sleep(random.randint(1, 3))
                with open('ticket.json', mode="w", encoding="utf-8")as f1:
                    json.dump(dic,f1)
                    print(f"{os.getpid()}购买成功")
    def task(lock):
        search()
        lock.acquire()
        paid()
        lock.release()
    if __name__ == '__main__':
        mutex = Lock()
        for i in range(6):
            p = Process(target = task,args = (mutex,))
            p.start()
    
    
    '''
    75543查看了票数,剩余1
    75544查看了票数,剩余1
    75548查看了票数,剩余1
    75545查看了票数,剩余1
    75543购买成功
    75546查看了票数,剩余0
    75547查看了票数,剩余0
    ''''
    

    总结:当很多资源共抢一个资源数据时,你要保证顺序(数据的安全),一定要串行

    互斥锁:可以公平性的保证顺序以及数据的安全

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

    2.基于队列通信

    队列 : 把队列理解成一个容器,这个容器可以加载一些数据

    1. 共享的空间
    2. 内存空间
    3. 自动帮我们处理好锁定问题

    Queue的特性 : 先进先出 FIFO

    from multiprocessing import Queue
    q = Queue()
    def func():
        print('in func')
    q.put(1)
    q.put("胖")
    q.put([1,2,3,4])
    q.put(func)
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get())
    '''
    1
    胖
    [1, 2, 3, 4]
    <function func at 0x109c1ba60>
    '''
    
    from multiprocessing import Queue
    q = Queue(3)
    q.put(1)
    q.put("alex")
    q.put([1,2,3])
    q.put(555)       #  当队列满了时,在进程 put 就会阻塞
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get())   # 当数据取完时,在进程get数据也会出现阻塞,直到某一个进程put数据.
    '''
    阻塞之后就直接不运行了,但是不报错
    '''
    

    block

    from multiprocessing import Queue
    q = Queue(3)
    q.put(1)
    q.put('alex')
    q.put([1,2,3])
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get(block = False ))
    '''
    只要遇到  block = False 阻塞就会报错
    '''
    

    timeout

    from multiprocessing import Queue
    q = Queue(3)
    q.put(1)
    q.put('alex')
    q.put([1,2,3])
    
    print(q.get())
    print(q.get())
    print(q.get())
    print(q.get(timeout = 3))
    '''
    阻塞 3 秒  3秒之后还阻塞就报错
    '''
    

    队列存成数据间沟通的消息时,数据量不应该过大

    maxsize 的值超过内存限制,将变得毫无意义

    3.基于管道通信

    生产者消费模型

    from multiprocessing import Process,Queue
    import time
    import os
    import 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()
    '''
    生产者坤坤生产了1号包子
    消费者海狗吃了1号包子
    生产者坤坤生产了2号包子
    生产者坤坤生产了3号包子
    消费者海狗吃了2号包子
    生产者坤坤生产了4号包子
    消费者海狗吃了3号包子
    生产者坤坤生产了5号包子
    消费者海狗吃了4号包子
    消费者海狗吃了5号包子
    '''

  • 相关阅读:
    如何学习区块链
    用Python从零开始创建区块链
    区块链入门
    什么是区块链
    localStorage使用总结
    整理vue学习笔记
    SCSS 教程
    vue — 创建vue项目
    软件开发的常见文档
    史上最全的CSS hack方式一览(转)
  • 原文地址:https://www.cnblogs.com/hualibokeyuan/p/11392222.html
Copyright © 2020-2023  润新知