Python並行程式設計(六):多執行緒同步之queue(佇列)實現生產者-消費者模型

若數發表於2019-04-13

方便的佇列

當我們處理多執行緒的資源共享時,執行緒模組的管理會變得很複雜。我們已經看到了,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函式進行等待。之後便可以開啟若干執行緒,執行緒的任務就是不斷的從佇列中取資料進行處理就可以了。

相關文章