1. 程式人生 > >python多線程編程-queue模塊和生產者-消費者問題

python多線程編程-queue模塊和生產者-消費者問題

獲取 區別 from html als 最大值 python3.6 .py python

摘錄python核心編程

本例中演示生產者-消費者模型:商品或服務的生產者生產商品,然後將其放到類似隊列的數據結構中。生產商品中的時間是不確定的,同樣消費者消費商品的時間也是不確定的。

使用queue模塊(python2.x版本中,叫Queue)來提供線程間通信的機制,從而讓線程之間可以分享數據。具體而言,就是創建一個隊列,讓生產者(線程)在其中放入新的商品,而消費者(線程)消費這些商品。

下表是queue模塊的部分屬性:

屬性 描述
queue模塊的類
Queue(maxsize=0) 創建一個先入先出隊列。如果給定最大值,則在隊列沒有空間時阻塞;否則,為無限隊列
LifoQueue(maxsize=0)
創建一個後入先出隊列。如果給定最大值,則在隊列沒有空間時阻塞;否則,為無限序列
PriorityQueue(maxsize=0) 創建一個優先級隊列。如果給定最大值,則在隊列沒有空間時阻塞;否則,為無限序列
queue異常
Empty 當對空隊列調用get*()方法時拋出異常
Full 當對已滿的隊列調用put*()方法時拋出異常
queue對象方法
qsize() 返回隊列大小。(由於返回隊列大小時可能被其他線程修改,所以該值為近似值)
empty() 如果隊列為空,則返回True,否則返回False
full() 如果隊列已滿,則返回True,否則返回False
put(item,block=True,timeout=None) 將item放入隊列。如果block為True(默認值),且timeout為None,則在有可用空間之前阻塞;如果timeout為正值,最多阻塞timeout秒;如果block為False,則拋出Empty異常
put_nowait(item) 和put(item,False)效果相同
get(block=True,timeout=None) 從隊列上取得元素。如果給定了block(非0),則一直阻塞直到有可用的元素為止
get_nowait() 和get(False)效果想用
task_done() 用於表示隊列中的某個元素已執行完成,該方法會被下面的join()使用
join() 在隊列中所有元素執行完畢並調用上面的task_done()信號前,保持阻塞。

下面的prodcons.py腳本中使用了queue對象實現了生產者-消費者場景,隨機生產或消費商品,且生產者和消費者獨立、並發的執行線程。註意,這裏使用了在之前章節中改寫的MyThread類

#python 3.6
from random import randint
from time import sleep
from queue import Queue
from myThread import MyThread
#將一個對象放入隊列中
def writeQ(queue):
    print(正在為隊列生產………)
    queue.put(商品,1)
    print(當前商品總數:,queue.qsize())
#消費隊列中的一個對象    
def readQ(queue):
    val = queue.get(1)
    print(正在從隊列中消費商品……消費後還剩余商品:,queue.qsize())
#模仿生產者。    
def writer(queue,loops):
    for i in range(loops):
        writeQ(queue)
        sleep(randint(1,3))#writer的睡眠時間一般比reader短,是為了阻礙 reader從空隊列中獲取對象,換句話說就是使得輪到reader執行時,已存在可消費對象的可能性更大。
#模仿消費者    
def reader(queue,loops):
    for i in range(loops):
        readQ(queue)
        sleep(randint(2,5))
    
funcs = [writer,reader]
nfuncs = range(len(funcs))

def main():
    nloops = randint(2,5)#randint 和randrange類似,區別在於,randrange是半開半閉區間,而randint是閉區間
    q = Queue(32)
    
    threads = []#模擬線程池
    for i in nfuncs:
        t = MyThread(funcs[i],(q,nloops),funcs[i].__name__)#創建線程
        threads.append(t)
        
    for i in nfuncs:
        threads[i].start()  #開始執行線程
        
    for i in nfuncs:
        threads[i].join()
        
    print(結束)
    
if __name__ == __main__:
    main()

執行效果類似:

PS C:\Users\WC> python E:\Python3.6.3\workspace\prodcons.py
開始執行 writer  在: Thu Apr 19 21:06:22 2018
正在為隊列生產………
開始執行 reader  在: Thu Apr 19 21:06:22 2018
當前商品總數: 1
正在從隊列中消費商品……消費後還剩余商品: 0
正在為隊列生產………
當前商品總數: 1
正在從隊列中消費商品……消費後還剩余商品: 0
正在為隊列生產………
當前商品總數: 1
正在從隊列中消費商品……消費後還剩余商品: 0
正在為隊列生產………
當前商品總數: 1
正在為隊列生產………
當前商品總數: 2
writer 結束於: Thu Apr 19 21:06:30 2018
正在從隊列中消費商品……消費後還剩余商品: 1
正在從隊列中消費商品……消費後還剩余商品: 0
reader 結束於: Thu Apr 19 21:06:39 2018
結束

python多線程編程-queue模塊和生產者-消費者問題