队列&生产者消费者
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放入队列中。
- 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。
- 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。
- 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常
其非阻塞版本为put_nowait
等同于put(item, False)
get([block[, timeout]])
从队列中移除并返回一个数据。block跟timeout参数同put
方法
其非阻塞方法为`get_nowait()`相当与get(False)
empty()
如果队列为空,返回True,反之返回False