方便的佇列
當我們處理多執行緒的資源共享時,執行緒模組的管理會變得很複雜。我們已經看到了,Python執行緒模組提供了很多同步原語,包括鎖、訊號量、條件變數、事件等。雖然有這麼多的選擇,但是使用佇列可能會是管理執行緒同步的最佳拍檔。佇列使用起來很容易,因為該模組提供了同步的,安全的對序列,包括FIFO(先入先出)佇列Queue,LIFO(後入先出)佇列LifoQueue,和優先順序佇列PriorityQueue.這些佇列都實現了鎖原語,能夠在多執行緒中直接使用。可以使用佇列來實現執行緒間的通訊: Queue模組中的常用方法:
- Queue.qsize():返回佇列的大小
- Queue.empty():如果佇列為空,返回True,反之False
- Queue.full():如果佇列滿了,返回True,反之False
- Queue.full:與 maxsize 大小對應
- Queue.get([block[, timeout]]):獲取佇列,timeout等待時間
- Queue.get_nowait() :相當Queue.get(False)
- Queue.put(item):寫入佇列,timeout等待時間
- Queue.put_nowait(item):相當Queue.put(item, False)
- Queue.task_done():在完成一項工作之後,Queue.task_done()函式向任務已經完成的佇列傳送一個訊號
- Queue.join():實際上意味著等到佇列為空,再執行別的操作
生產者-消費者模型
利用佇列實現生產者-消費者模型:
import threading
import queue
import random
import time
# 建立一個佇列
q = queue.Queue()
# 假定商品序號
item = 0
def produecr():
global item
while True:
time.sleep(1)
item = random.randint(1, 10)
# 將一個“商品”推到佇列中
q.put(item)
print('producer {}th gooos append to q.'.format(item))
time.sleep(1)
def consumer():
while True:
# 在佇列中刪除一個“商品”,並返回該“商品”
item = q.get()
print(threading.currentThread().getName() +
'consumer get {}th goods from q.'.format(item))
q.task_done()
if __name__ == "__main__":
threads_consumr = []
for i in range(3):
t = threading.Thread(target=consumer)
t.start()
threads_consumr .append(t)
thread_producer = threading.Thread(target=produecr)
thread_producer.start()
q.join()
for t in threads_consumr:
t.join()
thread_producer.join()
複製程式碼
執行截圖如下:
我們可以看到佇列的使用適用於這種經常發生的場景:比如當有成千上萬那的資料亟待處理,然後每次取出一條資料進行處理,如何利用多執行緒分配處理任務加快處理效率呢? 我們可以將資料進行分割然後交給多個執行緒去跑,可是這並不是一個明智的做法。在這裡我們可以使用佇列與執行緒相結合的方式進行任務分配。 可以利用佇列執行緒的思想: 首先建立一個全域性共享的佇列,佇列中只存在有限個元素,並將所有的資料逐條加入到佇列中,並呼叫佇列的join函式進行等待。之後便可以開啟若干執行緒,執行緒的任務就是不斷的從佇列中取資料進行處理就可以了。