起步
queue 模組提供適用於多執行緒程式設計的先進先出(fifo)資料結構。因為它是執行緒安全的,所以多個執行緒很輕鬆地使用同乙個例項。
原始碼分析
先從初始化的函式來看:
從這初始化函式能得到哪些資訊呢?首先,佇列是可以設定其容量大小的,並且具體的底層存放元素的它使用了collections.deque()雙端列表的資料結構,這使得能很方便的做先進先出操作。這裡還特地抽象為_init函式是為了方便其子類進行覆蓋,允許子類使用其他結構來存放元素(比如優先佇列使用了 list)。
然後就是執行緒鎖self.mutex,對於底層資料結構self.queue的操作都要先獲得這把鎖;再往下是三個條件變數,這三個 condition 都以self.mutex作為引數,也就是說它們共用一把鎖;從這可以知道諸如with self.mutex與with self.not_empty等都是互斥的。
基於這些鎖而做的一些簡單的操作:
這個**片段挺好理解的,無需分析。
作為佇列,主要得完成入隊與出隊的操作,首先是入隊:
儘管只有二十幾行的**,但這裡的邏輯還是比較複雜的。它要處理超時與佇列剩餘空間不足的情況,具體幾種情況如下:
1、如果 block 是 false,忽略timeout引數
若此時佇列已滿,則丟擲 full 異常;
若此時佇列未滿,則立即把元素儲存到底層資料結構中;
2、如果 block 是 true
若 timeout 是 none 時,那麼put操作可能會阻塞,直到佇列中有空閒的空間(預設);
若 timeout 是非負數,則會阻塞相應時間直到佇列中有剩餘空間,在這個期間,如果佇列中一直沒有空間,丟擲 full 異常;
處理好引數邏輯後,,將元素儲存到底層資料結構中,並遞增unfinished_tasks,同時通知not_empty,喚醒在其中等待資料的執行緒。
出隊操作:
get()操作是put()相反的操作,**塊也及其相似,get()是從佇列中移除最先插入的元素並將其返回。
1、如果 block 是 false,忽略timeout引數
若此時佇列沒有元素,則丟擲 empty 異常;
若此時佇列由元素,則立即把元素儲存到底層資料結構中;
2、如果 block 是 true
若 timeout 是 none 時,那麼get操作可能會阻塞,直到佇列中有元素(預設);
若 timeout 是非負數,則會阻塞相應時間直到佇列中有元素,在這個期間,如果佇列中一直沒有元素,則丟擲 empty 異常;
最後,通過self.queue.popleft()將最早放入佇列的元素移除,並通知not_full,喚醒在其中等待資料的執行緒。
這裡有個值得注意的地方,在put()操作中遞增了self.unfinished_tasks,而get()中卻沒有遞減,這是為什麼?
這其實是為了留給使用者乙個消費元素的時間,get()僅僅是獲取元素,並不代表消費者執行緒處理的該元素,使用者需要呼叫task_done()來通知佇列該任務處理完成了:
由於task_done()使用方呼叫的,當task_done()次數大於put()次數時會丟擲異常。
task_done()操作的作用是喚醒正在阻塞的join()操作。join()方法會一直阻塞,直到佇列中所有的元素都被取出,並被處理了(和執行緒的join方法類似)。也就是說join()方法必須配合task_done()來使用才行。
lifo 後進先出佇列
lifoqueue使用後進先出順序,與棧結構相似:
這就是 lifoqueue 全部**了,這正是 queue 設計很棒的乙個原因,它將底層的資料操作抽象成四個操作函式,本身來處理執行緒安全的問題,使得其子類只需關注底層的操作。
lifoqueue 底層資料結構改用 list 來存放,通過 self.queue.pop() 就能將 list 中最後乙個元素移除,無需重置索引。
priorityqueue 優先佇列
優先佇列使用了 heapq 模組的結構,也就是最小堆的結構。優先佇列更為常用,佇列中專案的處理順序需要基於這些專案的特徵,乙個簡單的例子:
使用優先佇列的時候,需要定義__lt__魔術方法,來定義它們之間如何比較大小。若元素的 priority 相同,依然使用先進先出的順序。
參考
python原始碼分析筆記 2
一.python中的整數物件 1.首先補充一下c語言知識的盲點,python底層都是用c寫的,看的時候發現自己還是有 看不懂,所有就先複習一下這些知識點。先說明 c語言中register關鍵字的作用 register修飾符暗示編譯程式相應的變數將被頻繁地使用,如果可能的話,應將其儲存在cpu的暫存器...
python原始碼剖析 Python原始碼剖析
第頁共 頁python 原始碼剖析 物件機制 1.物件 在python 的世界中,一切都是物件,乙個整數是乙個物件,乙個字串也是 乙個物件,更為奇妙的是,型別也是乙個物件,整數型別是乙個物件,字串類 型也是乙個物件。從 年guido 在那個聖誕節揭開 python 世界的大幕開始,一直到現在,pyt...
spring原始碼分析 spring原始碼分析
1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...