• Python学习之路并发编程--信号量、事件、队列及生产消费模型


    1. 信号量  

      对于多进程来说,多个进程同时修改数据,就可能出现安全隐患,所以引入了锁,这一机制,但锁只能有一把来控制一个的开关,当你需要几把锁的时候,就可能用到信号量的概念。他是用了锁的原理,内置了一个计数器,在同一时内,只能有指定数量的进程来执行某一段被控制的代码。

    import time,random
    from multiprocessing import Process,Semaphore
    
    def singing(i,sem):
        '''
        :param i: 随机生成20个数的值
        :param sem:生成的信号量
        :return:None
        '''
        sem.acquire()#获得锁
        print('%s is coming '%i)
        time.sleep(random.randint(10,20))#随机在10秒至20秒中停顿
        print('%s is going out'%i)
        sem.release()#释放锁
    
    if __name__ == '__main__':
        sem = Semaphore(4)#生成4个锁
        for i in range(20):
            p = Process(target=singing,args=(i,sem))
            p.start()

    2. 事件

      事件是通过一个信号来控制多个进程的同时执行或阻塞,当一个事件被创建的时候默认是阻塞状态,但不影响进程的执行,当遇到 even.wait() 方法时,才会阻塞。

    # set 和 clear
    #      分别用来修改一个事件的状态 True或者False
    # is_set 用来查看一个事件的状态
    # wait 是依据事件的状态来决定自己是否在wait处阻塞
    #      False阻塞 True不阻塞

      下面是一个红绿灯的问题。

    import time
    import random
    from multiprocessing import Event,Process
    
    def cars(e,i):
        '''
        一个判断车是否通过的函数
        :param e: 传入一个事件
        :param i: 生成的车几
        :return: None
        '''
        if not e.is_set():
            print('33[0;31;40mcar %s 在等待~33[0m'%i)
            e.wait()
        print('33[32;40mcar %s 通过~33[0m'%i)
    
    def light(e):
        '''
        控制红绿灯的切换
        :param e: 传入事件
        :return: None
        '''
        while True:
            if e.is_set():
                e.clear()
                print('33[31m红灯亮了33[0m')
                time.sleep(3)
            else:
                e.set()
                print('33[32m绿灯亮了33[0m')
                time.sleep(5)
    
    if __name__ == '__main__':
        e = Event()
        traffic = Process(target=light,args=(e,))
        traffic.start()
        time.sleep(1)
        for i in range(random.randint(5,10)):
            car = Process(target=cars,args=(e,i))
            car.start()
            time.sleep(random.randint(1,3))

    3. 队列

      队列 Queue 中只有少数几个方法,

        # put  当队列满的时候阻塞等待队列有空位置
        # get  当队列空的时候阻塞等待队列有数据
        # full empty 不完全准确

      full 和 empty 不准一原因在于,如果队列回答主程序时,同时进程又对队列进行了操作,这个就会造成数据的错误。

    4. 用 JoinableQueue 来处理生产者和消费者模型

    import time
    import random
    from multiprocessing import Process,JoinableQueue
    
    
    def producer(name,food,q):
        for i in range(4):
            time.sleep(random.randint(1,3))
            f = '%s生产了%s%s'%(name,food,i)
            print(f)
            q.put(f)
        q.join()    # 阻塞  直到一个队列中的所有数据 全部被处理完毕
    
    def consumer(q,name):
        while True:
            food = q.get()
            print('33[31m%s消费了%s33[0m' % (name,food))
            time.sleep(random.randint(1,3))
            q.task_done()     # count - 1
    
    if __name__  == '__main__':
        q = JoinableQueue(20)
        p1 = Process(target=producer,args=('eli','dumpling',q))
        p2 = Process(target=producer, args=('tom','noodle', q))
        c1 = Process(target=consumer, args=(q,'mike'))
        c2 = Process(target=consumer, args=(q,'johan'))
        p1.start()
        p2.start()
    
        c1.daemon = True   # 设置为守护进程 主进程中的代码执行完毕之后,子进程自动结束
        c2.daemon = True
    
        c1.start()
        c2.start()
        p1.join()
        p2.join()      # 感知一个进程的结束

      觉得最好的点就是用到了守护进程(当主进程的程序执行完成时,子进程也随之结束)。

  • 相关阅读:
    Spring系列(六):Spring事务源码解析
    Spring系列(五):Spring AOP源码解析
    Spring系列(四):Spring AOP详解
    Spring系列(三):Spring IoC源码解析
    Spring IoC源码解析之getBean
    Spring IoC源码解析之invokeBeanFactoryPostProcessors
    Spring系列(二):Spring IoC应用
    HDU-1276
    Codeforces Round #410 (Div. 2)-A
    ubuntu16.04安装wps
  • 原文地址:https://www.cnblogs.com/YS-0717/p/9742137.html
Copyright © 2020-2023  润新知