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

隊列

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

隊列分類

隊列有不少中,但都依賴模塊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.app

後進先出隊列

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能夠理解爲咱們這裏「倉庫」的地址,這樣就能夠實現點對點和廣播兩種方式進行消息的分發。
生產消費者模型圖線程

一句話總結

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

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()
相關文章
相關標籤/搜索