Python之queue模塊以及生產消費者模型


隊列

隊列類似於一條管道,元素先進先出,進put(arg),取get()
有一點需要注意的是:隊列都是在內存中操作,進程退出,隊列清空,另外,隊列也是一個阻塞的形態.

隊列分類

隊列有很多中,但都依賴模塊queue

隊列方式 特點
queue.Queue 先進先出隊列
queue.LifoQueue 后進先出隊列
queue.PriorityQueue 優先級隊列
queue.deque 雙線隊列

隊列的方法

方法 用法說明
put 放數據,Queue.put()默認有block=True和timeout兩個參數。當block=True時,寫入是阻塞式的,阻塞時間由timeout確定。當隊列q被(其他線程)寫滿后,這段代碼就會阻塞,直至其他線程取走數據。Queue.put()方法加上 block=False 的參數,即可解決這個隱蔽的問題。但要注意,非阻塞方式寫隊列,當隊列滿時會拋出 exception Queue.Full 的異常
get 取數據(默認阻塞),Queue.get([block[, timeout]])獲取隊列,timeout等待時間
empty 如果隊列為空,返回True,反之False
qsize 顯示隊列中真實存在的元素長度
maxsize 最大支持的隊列長度,使用時無括號
join 實際上意味着等到隊列為空,再執行別的操作
task_done 在完成一項工作之后,Queue.task_done()函數向任務已經完成的隊列發送一個信號
full 如果隊列滿了,返回True,反之False

單向隊列

import queue

q=queue.Queue(5)    #如果不設置長度,默認為無限長
print(q.maxsize)    #注意沒有括號
q.put(123)
q.put(456)
q.put(789)
q.put(100)
q.put(111)
q.put(233)
print(q.get())
print(q.get())

如此打印時候是阻塞的,為什么呢,因為創建了5個元素長度的隊列,但我put進去了6個,所以就阻塞了.如果少寫一個能顯示出正確的123.

后進先出隊列

q = queue.LifoQueue()
q.put(12)
q.put(34)
print(q.get())

優先級隊列

需要注意的是,優先級隊列put的是一個元組,(優先級,數據),優先級數越小,級別越高

q = queue.PriorityQueue()
q.put((3,'aaaaa'))
q.put((3,'bbbbb'))
q.put((1,'ccccc'))
q.put((3,'ddddd'))
print(q.get())
print(q.get())

out:

(1, 'ccccc')
(3, 'aaaaa')

雙線隊列

q = queue.deque()
q.append(123)
q.append(456)
q.appendleft(780)
print(q.pop())
print(q.popleft())

out:

456
780

生產消費者模型

解決什么問題,使用場景

從下面圖中可以發現生產者和消費者之間用中間類似一個隊列一樣的東西串起來。這個隊列可以想像成一個存放產品的“倉庫”,生產者只需要關心這個“倉庫”,並不需要關心具體的消費者,對於生產者而言甚至都不知道有這些消費者存在。對於消費者而言他也不需要關心具體的生產者,到底有多少生產者也不是他關心的事情,他只要關心這個“倉庫”中還有沒有東西。這種模型是一種松耦合模型。這樣可以回答我上面提出的第一個問題。這個模型的產生就是為了復用和解耦。比如常見的消息框架(非常經典的一種生產者消費者模型的使用場景)ActiveMQ。發送端和接收端用Topic進行關聯。這個Topic可以理解為我們這里“倉庫”的地址,這樣就可以實現點對點和廣播兩種方式進行消息的分發。
生產消費者模型圖

一句話總結

解決程序解耦,較少的資源解決高並發的問題

import queue,threading,time

q=queue.Queue()

def product(arg):
    while True:
        q.put(str(arg)+'包子')

def consumer(arg):
    while True:
        print(arg,q.get())
        time.sleep(2)
for i in range(3):
    t=threading.Thread(target=product,args=(i,))
    t.start()
for j in range(20):
    t=threading.Thread(target=consumer,args=(j,))
    t.start()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM