首頁 > 軟體

Python生產者與消費者模型中的優勢介紹

2023-03-27 06:01:35

生產者消費者模型具體來講,就是在一個系統中,存在生產者和消費者兩種角色,他們通過記憶體緩衝區進行通訊,生產者生產消費者需要的資料,消費者把資料做成產品,從而消耗掉生產的資料。達到供需平衡,不能生產多了浪費,也不能需要消耗資源的時候沒有。

multiprocessing-Queue實現

from  multiprocessing import Process,Queue  #多行程群元件,佇列
import time,random  
#生產者方法
def producer(name,food,q):
    for i in  range(4):
        time.sleep(random.randint(1,3)) #模擬獲取資料時間
        f = '%s生產的%s%s'%(name,food,i)
        print(f)
        q.put(f) #新增進佇列
#消費者方法
def consumer(q,name):
    while True:
        food = q.get() #如果獲取不到,會一直阻塞程序不會結束子程序
        # 當佇列中的資料是None的時候結束while迴圈
        if food is None:
            print('%s獲取到一個空'%name)
            break
        f = '33[31m%s消費了%s33[0m' % (name, food)
        print(f)
        time.sleep(random.randint(1,3)) # 模擬消耗資料時間
if __name__ == '__main__':
    q = Queue()  # 建立佇列
    # 模擬生產者 生產資料
    p = Process(target=producer, args=('p', '包子', q)) #建立程序
    p.start() #啟動程序
    p1 = Process(target=producer, args=('p1', '燒餅', q))
    p1.start()
   #模擬消費者消費資料
    c = Process(target=consumer, args=(q, 'c'))
    c.start()
    c1 = Process(target=consumer, args=(q, 'c1'))
    c1.start()
    p.join()#阻塞主程序 直到p和p1 子程序結束後才執行q.put() 方法
    p1.join()#阻塞主程序 直到p和p1 子程序結束後才執行q.put() 方法
    #為了確保生產者生產完所有資料後,
    #最後一個是None,方便結束子程序中的while迴圈,
    #否則會一直等待佇列中加入新資料。
    q.put(None)
    q.put(None)

使用Queue元件實現的缺點就是,實現了多少個消費者consumer程序,就需要在最後往佇列中新增多少個None標識,方便生產完畢結束消費者consumer程序。否則,p.get() 不到任務會阻塞子程序,因為while迴圈,直到佇列q中有新的任務加進來,才會再次執行。而我們的生產者只能生產這麼多東西,所以相當於程式卡死。

multiprocessing-JoinableQueue實現

from multiprocessing import JoinableQueue,Process
import time,random
#生產者方法
def producer(name,food,q):
    for i in range(4):
        time.sleep(random.randint(1, 2))
        f = '%s生產的%s%s'%(name,food,i)
        q.put(f)
        print(f)
    q.join()  #一直阻塞,等待消耗完所有的資料後才釋放
#消費者方法
def consumer(name,q):
    while True:
        food = q.get()
        print('33[31m%s消費了%s33[0m' % (name, food))
        time.sleep(random.randint(4,8))
        q.task_done() #每次消耗減1
if __name__ == '__main__':
    q = JoinableQueue()  #建立佇列
    #模擬生產者佇列
    p1 = Process(target=producer,args=('p1','包子',q))
    p1.start()
    p2 = Process(target=producer,args=('p2','燒餅',q))
    p2.start()
    #模擬消費者佇列
    c1 = Process(target=consumer,args=('c1',q))
    c1.daemon = True #守護行程:主程序結束,子程序也會結束
    c1.start()
    c2 = Process(target=consumer,args=('c2',q))
    c2.daemon = True
    c2.start()
    p1.join() #阻塞主程序,等到p1子程序結束才往下執行
    p2.join()
    # q.task_done() 每次消耗佇列中的 任務數減1
    # q.join() 一直阻塞,等待佇列中的任務數消耗完才釋放
    # 因為有 q.join 所有一直會等待 c1,c2 消耗完畢。才會執行 p.join 後面的程式碼
    # 因為 c1 c2 是守護行程,所以到這一步主程序程式碼執行完畢,主程序會釋放死掉,
    # 所以 c1 c2 也會跟隨 主程序釋放死掉。

  使用JoinableQueue元件,是因為JoinableQueue中有兩個方法:task_done()join() 。首先說join()Process中的join()的效果類似,都是阻塞當前程序,防止當前程序結束。但是JoinableQueuejoin()是和task_down()配合使用的。
  Process中的join()是等到子程序中的程式碼執行完畢,就會執行主程序join()下面的程式碼。而JoinableQueue中的join()是等到佇列中的任務數量為0的時候才會執行q.join()下面的程式碼,否則會一直阻塞。
  task_down()方法是每獲取一次佇列中的任務,就需要執行一次。直到佇列中的任務數為0的時候,就會執行JoinableQueuejoin()後面的方法了。所以生產者生產完所有的資料後,會一直阻塞著。不讓p1p2程序結束。等到消費者get()一次資料,就會執行一次task_down()方法,從而佇列中的任務數量減1,當數量為0後,執行JoinableQueuejoin()後面程式碼,從而p1p2程序結束。
  因為p1p2新增了join()方法,所以當子程序中的consumer方法執行完後,才會往下執行。從而主程序結束。因為這裡把消費者程序c1c2 設定成了守護行程,主程序結束的同時,c1c2 程序也會隨之結束,程序都結束了。所以消費者consumer方法也會結束。

到此這篇關於Python生產者與消費者模型中的優勢介紹的文章就介紹到這了,更多相關python生產者和消費者模型內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com