1. 程式人生 > >執行緒、程序、協程和GIL(三)

執行緒、程序、協程和GIL(三)

上一篇文章介紹了:建立縣城的兩種方式、Event物件判斷執行緒是否啟動、利用訊號量控制執行緒併發。

部落格連結:執行緒、程序、協程和GIL(二)

這一篇來說說執行緒間通訊的那些事兒: 

  一個執行緒向另一個執行緒傳送資料最安全的方式就是使用queue庫中的隊列了,通過建立一個供多個執行緒共享的Queue物件,這些執行緒使用put()和get()操作來向佇列中新增資料或者從佇列中取出資料,以達到執行緒間通訊的效果。

  queue佇列基本方法:

    queue.Queue(maxsize = num):  FIFO  先進先出佇列,如果maxsize小於或等於0 則代表隊列長度無線。

    queue.LifoQueue(maxsize = num): LIFO 後進先出佇列(類似於棧),如果maxsize小於或等於0 則代表隊列長度無線。

    Queue.qsize(): 返回當前佇列中元素的個數

         Queue.empty()   如果佇列為空,返回True,反之False 

         Queue.full()   如果佇列滿了,返回True,反之False

         Queue.get([block[, timeout]])   讀佇列,timeout等待時間 

         Queue.put(item, [block[, timeout]])   寫佇列,timeout等待時間 

         Queue.queue.clear()   清空佇列

  使用Queue構造生產者消費者模型來實現執行緒間的通訊:

import time
from queue import Queue,LifoQueue
from threading import
Thread def producer(in_q): while True: time.sleep(1) data = '包子' if in_q.full() == True: print('蒸籠滿了,放不下了') in_q.put(data) # 向佇列中塞東西 print('小明蒸%s!' %(data)) def customer(out_q): while True: time.sleep(3) if out_q.empty() == True: print('小紅沒取到包子,餓死了!') data = out_q.get() # 從佇列中取東西 print('小紅取 %s ' % (data)) if __name__ == '__main__': q = Queue(maxsize=3) t1 = Thread(target=producer, args=(q,)) t2 = Thread(target=customer, args=(q,)) t1.start() t2.start()

  上面的程式碼實現了一個簡單的生產者消費者,小明負責蒸包子,小紅負責吃包子。當佇列被包子塞滿時,小明就再也放不進去了,此時生產者這個執行緒就會阻塞。當小紅將佇列中的包子吃完時,消費者這個執行緒就會阻塞。因為Queue物件已經封裝了必要的鎖,所以我們可以在多個執行緒之間安全的功能共享資料。

  但是在生產者消費者的關閉問題會有一些麻煩,通用的解決方式就是在佇列中放置一個特殊值,當消費者讀到這個值時,就終止執行: