• 守护进程、互斥锁、生产者消费者模型


    一、守护进程

    1.定义:

    守护进程是守护父进程的子进程,所以守护进程实际上也是子进程的一类,守护进程会伴随着父进程的消亡而消亡。

    2.为什么有守护进程?

    当我们需要实现并发的目的的时候,就需要开启多个子进程。这些子进程中的某些子进程虽然将代码执行完毕,但是这类子进程们没有结束的运行条件,所以,这类子进程中的某些进程并不一定会随着父进程的毁灭而毁灭,但是这类进程又没有存在的意义了,这时候就需要用到守护进程。

    3.如何使用守护进程?

     1 from multiprocessing import Process
     2 import os,time
     3 def Foo():
     4     print('%s is eating..'%os.getpid())
     5     time.sleep(3)
     6     print('%s was eat over..'%os.getpid())
     7 
     8 def Bar():
     9     print('%s is going to school'%os.getpid())
    10     time.sleep(3)
    11     print('%s classes over'%os.getpid())
    12 
    13 if __name__ == '__main__':
    14     p1=Process(target=Foo)
    15     p2=Process(target=Bar)
    16     p1.daemon=True  # 这个代表p1是守护进程,而且必须写在子进程
    17                     # 向操作系统发起开启子进程信号之前
    18     p1.start()
    19     # p1.daemon=True   # AssertionError: process has already started
    20     p2.start()
    21     print("I'm main process")

    二、互斥锁

    1.定义:

    在涉及到共享数据的部分,需要将涉及到该部分的代码加上一个锁,使之变成串行(一个程序执行完毕,才会执行下一个程序)。

    2.为什么要有互斥锁?

    现如今的时代是个数据大爆发的时代,这就避免不了需要涉及到数据的共享,但这随之带来了数据安全性的问题。就拿平时网购这个问题来举例,假设一件商品的库存只剩下1件,这个时候多个客户端同时向服务端发送请求,申请查看该件商品的库存数据,服务端同时给各个客户端回应之后,在这之前都基本上没有什么大问题;但是在这之后,假如多个客户端同时又向服务端发送了一个购买的请求,在没有互斥锁的情况下,各个客户端都可以正常下单购买,但是我们的商品库存就只剩1件了!!!所以这种情况下,根本是不合理的。在有互斥锁的情况下,当各个客户端发送购买请求的时候,可以将这些请求按照请求的顺序排列,一个请求进入之后,其余的请求均只能在外面等待该请求的完成操作(不管购买成功或者下单失败)。这就是互斥锁存在的意义,当然前面的例子是在忽略网络延迟的前提下进行的。

    3.互斥锁使用例子

    3.1 多个客户端同时网购查看库存和下单购买示例

     1 from multiprocessing import Process,Lock
     2 import time,os,json,random
     3 # time.sleep()  是模拟网络延迟
     4 
     5 def look():
     6     time.sleep(random.randint(0,1))
     7     with open('a.txt','r',encoding='utf8') as f:
     8         dic=json.load(f)
     9     print('%s查到商品的库存是<%s>'%(os.getpid(),dic['count']))
    10 
    11 def buy():
    12     time.sleep(random.randint(0,2))
    13     with open('a.txt','rt',encoding='utf8') as f:
    14         dic=json.load(f)
    15     if dic['count']>0:
    16         dic['count']-=1
    17         with open('a.txt','wt',encoding='utf8') as f:
    18             json.dump(dic,f)
    19         print('%s 成功购买了该商品'%os.getpid())
    20     else:
    21         print('%s 商品库存不足,下单失败'%os.getpid())
    22 def get(mutex):
    23     look()
    24     with mutex:  # 给buy加上一个锁,同一时间只能有一个客户端进入
    25         buy()
    26 if __name__ == '__main__':
    27     mutex=Lock()
    28     for i in range(3):   # 用循环来模拟多个客户端
    29         p=Process(target=get,args=(mutex,))
    30         p.start()
    1 {"count":1}
    a.txt

    三、生产者消费者模型⭐⭐⭐⭐⭐⭐

    (1)了解生产者消费者模型之前,我们先来了解下 IPC 机制

      IPC 机制:Inter-Process Communication,进程间通信。IPC机制遵循的就是先进先出的原则

      IPC占用的是内存的空间,不应该往队列里边放大数据

      IPC 有两种实现方式:

      1.管道(PIPE) :一端只能放进去东西,而另一端只能从管道中取东西。

      2.队列(管道+锁) :在管道的前提下,为其添加上了一个锁,使之能够有顺序排列

    (2)示例

    from multiprocessing import Queue
    q=Queue(3)   # 将队列的空间设成3,默认是无限大,
                # 但是现实中碍于内存大小,它实际上还是有限制的
    q.put('cake')
    q.put('banana')
    q.put('cookies')
    # q.put('apple') # 队列满了之后不会在往队列里边添加任何东西了
    print(q.get())
    print(q.get())
    print(q.get())

    1.生产者消费者定义

      生产者:比喻的是程序运行中负责产生数据的任务

      消费者:比喻的是程序运行中负责处理数据的任务

    2.为何使用该模型?

      可以实现生产者与消费者之间的解耦和,生产者在不停生产的同时,消费者也可以不停的消费;这种情况下才能最大化的提高程序的运行效率,平衡了生产者的生产能力和消费者的消费能力。

    3.怎么使用?

      当我们的程序中明显的需要用到两个程序,一个程序不断地产生数据,而另一个程序不断地负责处理数据的时候,就需要用到该模型。

     1 from multiprocessing import Queue,Process
     2 import time,os,random
     3 
     4 def producer(name,food,q):
     5     for i in range(3):
     6         res='%s %s'%(food,i)
     7         time.sleep(random.randint(0,2))
     8         q.put(res)
     9         print('33[46m%s 生产了 %s33[0m'%(name,res))
    10     # q.put(None)  # q.put(None) 写在这里会造成消费者有可能还未销毁完,
    11                    # 然后这个None已经由生产者发送到消费者手中了,程序就运行结束了
    12 def consumer(name,q):
    13     while True:
    14         res=q.get()
    15         if res is None:break
    16         time.sleep(random.randint(1,3))
    17         print('%s 销毁了 %s '%(name,res))
    18 
    19 
    20 
    21 if __name__ == '__main__':
    22     q=Queue()
    23     # 生产者们
    24     p1=Process(target=producer,args=('大胖','火箭',q))
    25     p2=Process(target=producer,args=('二胖','坦克',q))
    26     p3=Process(target=producer,args=('三胖','原子弹',q))
    27 
    28     # 消费者们
    29     c1=Process(target=consumer,args=('小三',q))
    30     c2=Process(target=consumer,args=('小四',q))
    31 
    32     p1.start()
    33     p2.start()
    34     p3.start()
    35 
    36     c1.start()
    37     c2.start()
    38 
    39     p1.join()
    40     p2.join()
    41     p3.join()
    42 
    43     # 生产者生产完毕之后才应该放出结束信号
    44     q.put(None)  # q.put(None) 写在这里的意思是生产者都已经生产完毕,我们可以发 
    45                      # 送结束信号给消费者, 消费者收到信号之后,就会结束运行,不会一直等 
    46                       # 待接收生产者的产品了
    47     q.put(None)  # 若只写了一个q.put(None),则只有一个消费者会收到生产结束的信 
    48                        # 号,另一个消费者会继续等待接收,所以要写两个
    49     print('supervisor')
    生产者消费者低配版
     1 from multiprocessing import Process,JoinableQueue
     2 import time,random
     3 
     4 def producer(name,product,q):
     5     for i in range(3):
     6         res='%s %s'%(product,i)
     7         time.sleep(random.randint(0,2))
     8         print('33[46m %s produce %s 33[m'%(name,res))
     9         q.put(res)
    10 
    11 def consumer(name,q):
    12     while True:
    13         res=q.get()
    14         time.sleep(random.randint(0,2))
    15         print('%s eat %s'%(name,res))
    16         q.task_done()   # 代表队列里边的值已经被取光了,
    17                         # 取光了就说明生产者已经全部生产完了,
    18                         # 并且消费者也都消费完了
    19 
    20 
    21 if __name__ == '__main__':
    22     q=JoinableQueue()
    23     p1=Process(target=producer,args=('A','cake',q))
    24     p2=Process(target=producer,args=('B','sun',q))
    25     p3=Process(target=producer,args=('C','moon',q))
    26 
    27     c1=Process(target=consumer,args=('GG',q))
    28     c2=Process(target=consumer,args=('MM',q))
    29     c1.daemon=True
    30     c2.daemon=True   # 主进程结束之后消费者的进程也会随之结束
    31     # 消费者再吃完之后,虽然任务已经完成,但是消费者还是会继续等待接收,
    32     # 为了结束程序,我们可以将消费者设置成守护进程,伴随主进程的消亡而消亡
    33     
    34     
    35     p1.start()
    36     p2.start()
    37     p3.start()
    38 
    39     c1.start()
    40     c2.start()
    41 
    42     p1.join()
    43     p2.join()
    44     p3.join()
    45 
    46     q.join()   # 这里的意思是管道队列里的东西取完之后,才会运行父进程的代码(前提是下面还有代码)
    47                
    48     print('main process'.center(20,'-'))
    生产者消费者升级版
  • 相关阅读:
    Using AlloyTouch to control three.js 3D model
    AlloyTouch与three.js 3D模型交互
    移动Web触摸与运动解决方案AlloyTouch开源啦
    transformjs玩转星球
    swing with transformjs
    和transformjs一起摇摆
    getting started with transformjs
    移动Web利器transformjs入门
    腾讯AlloyTeam移动Web裁剪组件AlloyCrop正式开源
    Why AlloyFinger is so much smaller than hammerjs?
  • 原文地址:https://www.cnblogs.com/Smart1san/p/9301440.html
Copyright © 2020-2023  润新知