zoukankan      html  css  js  c++  java
  • 队列&生产者消费者

    Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用多线程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间信息传递.

    如果在多线程中,给存放数据,也就是修改同一份数据, 所以就需要上锁   但是在列队这不用加

    因为!!队列是线程安全的,存储数据的时候,程序就会给上锁,  能够保证数据的唯一性.

    1.先入先出  fisrt in fisrt out  ---> queue.Queue()           FIFO队列

    2.后入先出  last in fisrt out  ----> queue.LifoQueue()   LIFO队列

    3.优先级队列           ----->queue.PriorityQueue()

     1 import queue
     2 
     3 ###先进先出
     4 q1=queue.Queue(maxsize=3)          #这里设置是可以存放多少个队列  如果设置了3个 但是q.put达到3个以上  ,就会阻塞  因为这是队列 先进先出
     5 q1.put(1)
     6 q1.put(2)
     7 q1.put(3)
     8 
     9 ###权重 优先级
    10 q2=queue.PriorityQueue()
    11 q2.put([6,'alex'])
    12 q2.put([3,'zhaichaoqun'])
    13 q2.put([10,'renchenghon'])
    14 
    15 ###后进先出
    16 q3=queue.LifoQueue()
    17 q3.put([6,'alex'])
    18 q3.put([3,'zhaichaoqun'])
    19 q3.put([10,'renchenghon'])
    20 
    21 
    22 print(q1.empty()) #判断是不是为空   不空为False
    23 print(q1.full())    #判断是不是满
    24 print(q1.qsize())  #队列大小
    25 
    26 #因为是队列  不能跳着取。 必须一个一个取 遵循先进先出
    27 print(q1.get())  #get是用来取第一个值   并在队列中取消这个
    28 print(q1.get())  #get是用来取第二个值
    29 print(q1.get())  #get是用来取第三个值
    30 print('取完后队列',q1.qsize())
    31 
    32 print(q2.get())
    33 print(q2.get())
    34 print(q2.get())
    35  #这里get  如果没有值 就一直等待
    36 print('---')
    37 print(q3.get())
    38 print(q3.get())
    39 print(q3.get())

      q1.empty()  判断是不是为空

      q1.full() 判断队列是不是满了    #如果满了。在往队列中放数据就会卡住.

      q1.qsize() 队列大小

    生产者消费者

    来段实例代码看看

    import queue
    import time
    import threading
    
    def consumer(name):  #这就是定义的消费者。。。。   因为去q.get 队列中的值
        while True:
            print('%s 取得蛋糕 %s并吃了它' %(name,q.get()))   #q.get 就是去队列中取值
            time.sleep(0.5)
            q.task_done()  #回执
    def produce(name):
        count=0
        #while q.qsize() <5:  #因为队列设置的大小为4  那么这里设置小于5,因为上面会取。队列就会取,所以这里会一直进行下去
        for i in range(10):
            print("%s生产了%s个蛋糕" %(name,count))
            q.put(count)
            count +=1
            #time.sleep(2)
        q.join()   #直到队列被消费完毕  
        print('生产完了------')
    q=queue.Queue(maxsize=4) #设置队列大小为4
    #创建线程
    p1=threading.Thread(target=consumer,args=('rch',))
    p2=threading.Thread(target=produce,args=('zcq',))
    p1.start()
    p2.start()

    consumer 定义的消费者

    produce 定义的生产者

    这里有个点要记下:

      1.这里用到了q.task_done()  

        A。这里的作用是,每个消费者在消费完这个任务之后, 都要给你的生产者发送一个回执,生产者收集完所有的回执,就会判断所有的任务是不是都运行结束了,如果是,就可以结束了

        B。这里用到了join  ,跟前面是一样的,  这里就是等待所有子线程回执都回来, 才运行主线程.

    这里可以一直增加生产者,或者消费者  。

    生产者消费者的2个主要作用

    1.程序的解耦合

    2.提高了程序的运行效率

    task_done()

    意味着之前入队的一个任务已经完成。由队列的消费者线程调用。每一个get()调用得到一个任务,接下来的task_done()调用告诉队列该任务已经处理完毕。

    如果当前一个join()正在阻塞,它将在队列中的所有任务都处理完时恢复执行(即每一个由put()调用入队的任务都有一个对应的task_done()调用)。

    join()

    阻塞调用线程,直到队列中的所有任务被处理掉。

    只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。

    put(item[, block[, timeout]])

    将item放入队列中。

    1. 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。
    2. 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。
    3. 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常

    其非阻塞版本为put_nowait等同于put(item, False)

    get([block[, timeout]])

    从队列中移除并返回一个数据。block跟timeout参数同put方法

    其非阻塞方法为`get_nowait()`相当与get(False)

    empty()

    如果队列为空,返回True,反之返回False

  • 相关阅读:
    初识Activity
    贝叶斯公式由浅入深大讲解—AI基础算法入门【转】
    jz2440使用openjtag+openocd+eclipse调试【学习笔记】
    win10下搭建jz2440v3(arm s3c2440)开发及gdb调试环境【转】
    Eclipse安装zylin[转]
    Ubuntu 16.04下EasyOpenJTAG+OpenOCD的安装和使用【转】
    如何退出minicom【学习笔记】
    Python Matplotlib简易教程【转】
    anacoda的spyder在调用matplotlib的时候无法显示动画效果【学习笔记】
    Spyder如何在弹出框绘图【转】
  • 原文地址:https://www.cnblogs.com/zcqdream/p/6171249.html
Copyright © 2011-2022 走看看