1、隊列queuehtml
隊列queue 多應用在多線程場景,多線程訪問共享變量。python
對於多線程而言,訪問共享變量時,隊列queue的線程安全的。安全
由於queue使用了一個線程鎖(pthread.Lock()),以及三個條件變量(pthread.condition()),來保證了線程安全。多線程
總結:隊列提供了一個安全可靠的共享數據使用方案。app
隊列內置控制安全的幾個參數,非用戶使用 | 名稱 | 做用 |
self.mutex | 互斥鎖 | 任何獲取隊列的狀態(empty(),qsize()等),或者修改隊列的內容的操做(get,put等)都必須持有該互斥鎖。共有兩種操做require獲取鎖,release釋放鎖。同時該互斥鎖被三個共享變量同時享有,即操做conditiond時的require和release操做也就是操做了該互斥鎖。 |
self.not_full | 條件變量dom 隊列沒滿ide |
當隊列中有元素添加後,會通知notify其餘等待添加元素的線程,喚醒等待require互斥鎖,或者有線程從隊列中取出一個元素後,通知其它線程喚醒以等待require互斥鎖。 |
self.not_empty | 條件變量函數 隊列不爲空ui |
線程添加數據到隊列中後,會調用self.not_empty.notify()通知其它線程,喚醒等待require互斥鎖後,讀取隊列。 |
self.all_tasks_done | 條件變量spa 隊列數據所有處理完 |
消費者線程從隊列中get到任務後,任務處理完成,當全部的隊列中的任務處理完成後,會使調用queue.join()的線程返回,表示隊列中任務以處理完畢。 |
###queue的初始化函數### def __init__(self, maxsize=0): self.maxsize = maxsize self._init(maxsize) # mutex must be held whenever the queue is mutating. All methods # that acquire mutex must release it before returning. mutex # is shared between the three conditions, so acquiring and # releasing the conditions also acquires and releases mutex. self.mutex = _threading.Lock() # Notify not_empty whenever an item is added to the queue; a # thread waiting to get is notified then. self.not_empty = _threading.Condition(self.mutex) # Notify not_full whenever an item is removed from the queue; # a thread waiting to put is notified then. self.not_full = _threading.Condition(self.mutex) # Notify all_tasks_done whenever the number of unfinished tasks # drops to zero; thread waiting to join() is notified to resume self.all_tasks_done = _threading.Condition(self.mutex) self.unfinished_tasks = 0
2、隊列數據存取規則:
數據使用方式 |
類名 |
做用 | 示例 |
FIFO先進先出 |
Queue(maxsize) |
先進入隊列的數據,先取出 maxsize:>=0 設置隊列長度,0爲無限長 |
q = queue.Queue() |
FILO先進後出 |
LifoQueue(maxsize) |
先進入隊列的數據,最後取出 maxsize:>=0 設置隊列長度,0爲無限長 |
q = queue.LifoQueue() |
Priority優先級 |
PriorityQueue(maxsize) |
設置優先標誌,優先取出高標誌位 maxsize:>=0 設置隊列長度,0爲無限長 |
q = queue.PriorityQueue() |
###例子一:先進先出### import queue q = queue.Queue() for i in range(5): q.put(i) for i in range(5): print(q.get(),end=" ") #---結果--- 0 1 2 3 4 ###例子二:後進先出### import queue q = queue.LifoQueue() for i in range(5): q.put(i) for i in range(5): print(q.get(),end=" ") #---結果--- 4 3 2 1 0 ###例子三:按優先標誌位讀取### #參考其它資料,看到許多講述優先級隊列的實現,可是我以爲直接用元組的方式比較簡單粗暴。 import queue p = queue.PriorityQueue() p.put((3,"3")) p.put((1,"1")) p.put((4,"4")) p.put((2,"2")) for i in range(3): print(p.get()) #---結果:按元組索引0排序--- (1, '1') (2, '2') (3, '3') (4, '4') ###例子四:多元組判斷### import queue p = queue.PriorityQueue() p.put((1,4,"a")) p.put((2,1,"666")) p.put((1,3,"4")) p.put((2,2,"2")) for i in range(3): print(p.get()) #-----結果:元組對應的序號進行比較,主鍵是序號0,越日後,優先度越低。----- (1, 3, '4') (1, 4, 'a') (2, 1, '666') (2, 2, '2')
三、隊列的經常使用方法和屬性:
方法和屬性 | 做用 |
示例 |
task_done() | 一、標記以前的一個任務已經完成。 二、由隊列的消費者線程調用。每個get()調用獲得一個任務,接下來的task_done()調用告訴隊列該任務已經處理完畢。 三、若是當前的join()當前處於阻塞狀態,當前的全部元素執行後都會重啓(意味着收到加入queue的每個對象的task_done()調用的信息) |
|
join() |
阻塞: 等待隊列全部任務執行結束。 當消費者線程調用task_done(),隊列中未完成的計數就會減小,直至計數爲0,解除阻塞。 |
|
put(item,block,timeout) |
把對象item放入隊列: item:對象名稱,必填項。 block: 默認是True,若是隊列滿等待。 設置成False,若是隊列滿報Full異常。 timeout:【block爲True是生效】 默認是None,若是隊列滿了等待。 0:不等待,隊列滿了當即報Full。 正數1~:等待相應秒數,秒數到了,隊列仍是滿的,報錯Full。
|
|
put_nowait(item) | 向隊列裏存對象,不等待,若是隊列滿了,報queue.Full錯誤 | |
get(block,timeout) |
從隊列取出對象,並把對象從隊列中刪除 block: 默認是True,隊列爲空等待。 能夠變動爲False,若是隊列爲空,報Empty錯誤。 timeout:【block爲True是生效】 默認是None,隊列爲空,等待。 0:不等待,隊列爲空直接報Empty。 正數1~:等待相應秒數,若是依然爲空,則報Empty
|
|
get_nowait() | 從隊列裏取對象,不等待,若是隊列爲空,報queue.Empty錯誤 | |
qsize() |
返回隊列長度的近似值。 qsize長度不作爲get和put方法的操做依據。
|
|
empty() |
隊列爲空返回True 不作爲get和put方法的操做依據。
|
|
full() |
隊列滿了返回True 不作爲get和put方法的操做依據。
|
4、隊列數據進出規則實例 :
也是一個最簡單的生產者消費者例子。
'''例子一:隊列基本的進出規則''' import queue,time,threading,random def productor(name,s): # 生產者函數,向隊列裏放產品 time.sleep(s) print ('服務員{}有時間了'.format(name)) q.put(name) def customer(): # 消費者函數,從隊列裏取產品 s = q.get() print ('服務員{}被叫走了'.format(s)) l = [] q = queue.LifoQueue() # 後進先出,把LifoQueue改爲Queue,先進先出。 for i in range(5): n = random.randint(1,7) t = threading.Thread(target=productor,args=(i,n)) # 生產線程 l.append(t) t.start() for i in l: i.join() customer() #-----運行結果:由於有Random,因此結果不固定,主要觀察消費順序。------ 服務員0有時間了 服務員0被叫走了 服務員1有時間了 服務員1被叫走了 服務員4有時間了 服務員3有時間了 服務員2有時間了 服務員2被叫走了 服務員3被叫走了 服務員4被叫走了
參考資料:
http://python.jobbole.com/87592/