首先我們要明白為什麼要使用隊列,隊列的性質,
多線程 並發編程 的重點,是線程之間共享資料的訪問問題和線程之間的通訊問題。 為了解決線程之間資料共享問題,PYTHON 提供了一個資料型別【隊列】,可以用於在多線程並發模式下,安全的訪問資料而不會造成資料共享衝突。
正常請求的多線程,如果是消費者和生產者,通過列表實現,多線程會對列表中的資料取值,會出現同時訪問列表資料的情況,這時候就需要對線程進行加鎖或者是線程等待,手動進行解決,過於麻煩,但是隊列會通過先進先出或者先進後出的模式,保證了單個資料不會同時被多個線程訪問。
Queue.Queue(maxsize=0)
FIFO 即 First in First Out,先進先出。Queue 提供了一個基本的 FIFO 容器,使用方法很簡單,maxsize 是一個整數,指明了隊列中能存放的數據個數的上限。一旦達到上限,插入會導致阻塞,直到隊列中的數據被消費掉。如果 maxsize 小於或等於 0,隊列大小沒有限制。
Queue.LifoQueue(maxsize=0)
LIFO 即 Last in First Out,後進先出。與棧的類似,使用也很簡單,maxsize 用法同上。
構造一個優先隊列,maxsize 用法同上。
Queue.Queue(maxsize=0)
# FIFO,用來定義隊列的長度,如果 maxsize 小於 1 就表示隊列長度無限
Queue.LifoQueue(maxsize=0)
# LIFO,如果 maxsize 小於 1 就表示隊列長度無限
Queue.qsize()
# 返回隊列的大小
Queue.empty()
# 如果隊列為空,返回 True,反之 False。在線程間通訊的過程中,可以通過此來給消費者等待訊息
Queue.full()
# 如果隊列滿了,返回 True,反之 False,給生產者提醒
Queue.get([block, timeout])
# 讀取隊列,timeout 等待時間
Queue.put(item, [block, timeout])
# 寫隊列,timeout 等待時間
Queue.queue.clear()
# 清空隊列
task_done()
# 意味著之前隊列的一個任務已經完成。由隊列的消費者線程調用。每一個 get() 調用得到一個任務,接下來的 task_done()調用告訴隊列這個任務已經處理完畢。如果前一個 join() 正在阻塞,它將在隊列中的所有任務都處理完時恢復執行(即每一個由 put() 調用入隊的任務都有一個對應的 task_done() 調用)。
join()
# 阻塞調用線程,直到隊列中的所有任務被處理掉。只要有數據被加入隊列,未完成的任務數就會增加。當消費者線程調用 task_done()(意味著有消費者取得任務並完成任務),未完成的任務數就會減少。當未完成的任務數到 0,join() 解除阻塞。
Python 多線程主要是為了提高程序在 I/O 方面的優勢,在爬蟲的過程中顯得尤其重要。正常的爬蟲請求直接封裝多線程就 ok,但是爬蟲請求的過程中,對於 url 的請求需要通過隊列來實現,這是隊列的需求之一。
對於爬蟲的請求地址來說,一般是有順序性的,如果是爬頁數數據,可以將請求到的 url 放到隊列中,通過多線程對隊列進行取數據,如此隊列為空,線程判斷自動等待,循環加入隊列,線程自動請求,以示例代碼作為參考:
以上程式碼是作者從資料庫中取資料,間隔性地取出,然後拼接到 URL,再進行請求。