zoukankan      html  css  js  c++  java
  • 守护进程 互斥锁 PIC 生产者与消费者模型

    1守护进程

      定义:一个进程可以守护另一个进程
      eg:如果b是a的守护进程,a是被守护的进程,a完了,b也shui随之完了,qq 接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了qq,下载任务就没必须要继续运行了

      应用场景:父进程交给子进程一个任务,任务还没完成,父进程就结束了,子进程就没有继续执行的意义了

    from multiprocessing import Process
    import time
    
    # 妃子的一生
    def task():
        print("入宫了.....")
        time.sleep(50)
        print("妃子病逝了......")
    
    
    if __name__ == '__main__':
        # 康熙登基了
        print("登基了.....")
    
        # 找了一个妃子
        p = Process(target=task)
    
        # 设置为守护进程 必须在开启前就设置好
        p.daemon = True
        p.start()
    
        # 康熙驾崩了
        time.sleep(3)
        print("故事结束了!")

    2.互斥锁

      定义:相互排斥的锁(如果这个资源被锁了,其他程序就无法执行了)

      注:锁,并不是 把资源给锁起来了,只是在代码层面限制你的代码无法执行

      why要锁:并发会带来资源的竞争问题,多比如说个进程同时操作同一个资源时,会导致数据错乱

      解决方法:1.直接加join

            弊端:1.会把原本并发的任务变成串行,虽然避免了数据的错乱,但效率降低了,这样的话,就没必开烤子了

                        2.原本多个进程是公平竞争,加join后,执行的顺序就定死了,不合理

           2.给公共资源加互斥锁,这样依然是公平竞争,谁先抢到,谁先执行,父进程可做其他的事

      锁与join的区别:

          join:会固定死执行顺序,会造成父进程等子进程,他是吧进程的任务全部串行
          锁:还是公平竞争,谁先抢到谁先执行,锁可以锁任意代码,一行代码也行,可以自己调粒度

          颗粒:   一种级别,颗粒越大锁住的代码越多,效率越低,反之亦然。

                    

       注:1.一次acquire对应一次release,不要把锁给锁了,这样程序就无法执行了

         2.想要保护数据安全,必须保证所有进程使用同一把锁

    from multiprocessing import Process,Lock
    import time,random
    
    def task1(lock):
        # 要开始使用了 上锁
        lock.acquire()       #就等同于一个if判断
        print("hello iam jerry")
        time.sleep(random.randint(0, 2))
        print("gender is boy")
        time.sleep(random.randint(0, 2))
        print("age is  15")
        # 用完了就解锁
        lock.release()
    
    def task2(lock):
        lock.acquire()
        print("hello iam owen")
        time.sleep(random.randint(0,2))
        print("gender is girl")
        time.sleep(random.randint(0,2))
        print("age is  48")
        lock.release()
    
    def task3(lock):
        lock.acquire()
        print("hello iam jason")
        time.sleep(random.randint(0,2))
        print("gender is women")
        time.sleep(random.randint(0,2))
        print("age is  26")
        lock.release()
    
    if __name__ == '__main__':
        lock = Lock()
    
        p1 = Process(target=task1,args=(lock,))
        p2 = Process(target=task2,args=(lock,))
        p3 = Process(target=task3,args=(lock,))
    
        p1.start()
        # p1.join()
    
        p2.start()
        # p2.join()
    
        p3.start()
        # p3.join()
    
        # print("故事结束!")
        
    # 锁的伪代码实现 
    
    # if my_lock == False:
    #     my_lock = True
    #      #被锁住的代码
          my_lock = False 解锁

    3.ipc

      定义:IPC是进程间的通询,也就是一个进程把数据交给另一个进程,进程间内存相互隔离,想要通讯要用ipc  

      方式:1.管道:只能单向通讯,数据都是二进制,

         2.文件:在硬盘上创建共享文件,数据量几乎没有限制,但是速度慢

         3.socket:编程复杂度高,

         4共享内存:

          1.Manager:它提供很多数据结构  list   dict 等,它提供的数据结构具备进程间共享的特点

            注:Manager创建的一些数据结构是不带锁的,可能会出问题

    from multiprocessing import Process,Manager,Lock
    import time
    
    
    def task(data,l):
        l.acquire()
        num = data["num"] #
        time.sleep(0.1)
        data["num"] = num - 1
        l.release()
    
    if __name__ == '__main__':
        # 让Manager开启一个共享的字典
        m = Manager()
        data = m.dict({"num":10})
    
        l = Lock()
    
        for i in range(10):
            p = Process(target=task,args=(data,l))
            p.start()
    
        time.sleep(2)
        print(data)

          2.Queue队列

            队列:队列是一种特殊的数据结构,先进先出,就像排队

            堆栈:先进后出,就像衣橱,桶装薯片

            扩展:函数嵌套调用时   指执行顺序先进后出,  称之为函数栈

              调用函数时,函数入栈,函数结束就出栈

    from multiprocessing import Queue
    # 创建队列  不指定maxsize 则没有数量限制
    q = Queue(3)
    # 存储元素
    # q.put("abc")
    # q.put("hhh")
    # q.put("kkk")
    
    # print(q.get())
    # q.put("ooo")    # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行
    
    #取出元素
    # print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续
    
    # print(q.get())
    # print(q.get())
    
    
    #block 表示是否阻塞 默认是阻塞的   # 当设置为False 并且队列为空时 抛出异常
    q.get(block=True,timeout=2)
    # block 表示是否阻塞 默认是阻塞的   # 当设置为False 并且队列满了时 抛出异常
    # q.put("123",block=False,)
    # timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常  仅在block为True有效

    4.生产者消费者  模型

      定义:解决 产生数据与处理数据的 问题的一种套路

      生产者与消费者的问题:他们两者处理速度不平衡,一方快一放慢,导致一方需要等待另一方

      解决问题的思路:

        原本双方是耦合在一起,消费必须等待生产者生成完毕,再开始处理,反之亦然;

        现在,可以把双方分开,一方负责生产,一方负责处理,这样数据就不能直接交互了,双方需要一个共同的容器。然后生产者放入容器,消费者取出数据。这样就解决了两者处理速度不平衡的问题,都可以自己做自己的,无需等待。

    def eat(q):
        for i in range(10):
            # 要消费
            rose = q.get()
            time.sleep(random.randint(0, 2))
            print(rose,"吃完了!")
    
    # 生产任务
    def make_rose(q):
        for i in range(10):
            # 再生产
            time.sleep(random.randint(0, 2))
            print("第%s盘青椒肉丝制作完成!" % i)
            rose = "第%s盘青椒肉丝" % i
            # 将生成完成的数据放入队列中
            q.put(rose)
    
    if __name__ == '__main__':
        # 创建一个共享队列
        q = Queue()
        make_p = Process(target=make_rose,args=(q,))
        eat_p =  Process(target=eat,args=(q,))
    
    
        make_p.start()
        eat_p.start()

         

  • 相关阅读:
    ABAP TCode
    SAP 常用的事务代码
    SAP FI TCode
    Little Tutorials的一篇文章断言:UML(统一建模语言)正在死亡:
    SAP PP TCode
    [ZT]解密中国IT人十大职业现状
    User Exit Query
    SAP客户端多语言设置
    一个女CIO的诞生
    DIY防奸手册之 主流硬盘型号解惑篇
  • 原文地址:https://www.cnblogs.com/wyf20190411-/p/10969412.html
Copyright © 2011-2022 走看看