1. 程式人生 > >Python35 events(事件)、隊列

Python35 events(事件)、隊列

python

事件(events)
基於event實現綠燈舉例的多線程 程序

def lighter():
    count = 0
    event.set()
    ##先設置標誌位為真,表示初始狀態就是綠燈。否則當下面的if count > 5之前,標誌位都是沒有被設置的
    while True:
        if count > 5 and count <10: #大於5並且小於10就改成紅燈
            # 這裏代碼不能只寫成if count > 5,因為只要滿足大於5,就不會去匹配大於10的elif條件了。
            event.clear()   #把標誌位清空,檢查標誌位,如果標誌位沒有被設置,則當做紅燈。
            print ("\033[41;1m red light is on...\033[0m")
            ## 這裏>5 and <10的數是6-9,所以這裏會打印紅燈4次。
        elif count > 10:    #紅燈到綠燈期間設置時間為10秒,當大於30時,設置標誌位
            event.set() #設置標誌位,檢查到這個標誌位,就當做已經綠燈
            count = 0   #用count來計數多少秒,當設置為綠燈時就清空為0秒,20秒後就紅燈
        else:
            print("\033[42;1m green light is on...\033[0m")
            ## 匹配count既不大於5,也不大於10時(也就是小於5時),打印綠燈亮
            ## 這裏0-5會打印綠燈6次。

        time.sleep(1)   #設置每一秒循環一次,這樣20秒後就紅燈,20秒到30秒後就變成綠燈。
        count += 1

def car(name):
    while True:
        if event.is_set():  #這裏判斷如果事件設置了標誌位(表示綠燈)
            print ("[%s] running..." %name)
            time.sleep(1)
        else:   #標誌位為空表示紅燈
            print ("[%s] sees red light, waiting......" %name)
            event.wait()    #如果判斷標誌位為空,則阻塞程序,直到標誌位為真。
            print ("[%s] green light is on, start going... "%name)

light = threading.Thread(target=lighter,)
light.start()

car1 = threading.Thread(target=car,args=("car1",))
car1.start()

執行結果:
技術分享圖片
可以看到綠燈時,車就正常行駛; 紅燈時就等待。


隊列(queue)

FIFO(先進先出)

隊列的作用:
1、解耦:避免兩者之間的過度依賴,以免其中一方出現問題,另一方不能再執行。
2、效率:增加數據處理的效率。

隊列可以理解為一個容器,用來放數據的,不過這個容器中的數據是有順序的。


import queue

q = queue.Queue()   #先生成一個隊列對象
q.put("d1") #將d1這個數據放入隊列中
q.put("d2") #將d2這個數據也放入隊列中
q.put("d3")

q.qsize()   # 來查詢當前隊列數據數量

print (q.get()) #這裏不能取出指定的數據,只能根據先進先出的順序來取出數據,所以這裏取出的是"d1"這個數據
print (q.get()) #這裏取出的是"d2"這個數據
print (q.get()) #這裏取出的是"d3"這個數據

執行結果:
d1
d2
d3
## 先進先出的順序來get數據

10辦公


import queue

q = queue.Queue()   
q.put("d1") 
q.put("d2") 
q.put("d3")

q.qsize()   

print (q.get()) 
print (q.get()) 
print (q.get()) 

print (q.get()) 
## 之前只進入了3個數據,且3個數據也被取出了,此時數據為空,我再次取數據就會卡在這,因為沒有數據了,會一直卡在這等待新的數據進來

執行結果:

技術分享圖片
可以看到程序卡主了。


import queue

q = queue.Queue()
q.put("d1")
q.put("d2")
q.put("d3")

q.qsize()

print (q.get())
print (q.get())
print (q.get())

print (q.get(block=False))
## 默認就存在block=True這個參數,True的話表示如果數據為空就卡主,設置False就不卡主

技術分享圖片
不在卡主,並且拋出異常

import queue

q = queue.Queue()
q.put("d1")
q.put("d2")
q.put("d3")

q.qsize()

print (q.get())
print (q.get())
print (q.get())

print (q.get(timeout=3))
## 設置如果卡主的話,卡多久,這裏設置為卡3秒

技術分享圖片
卡3秒後,依然沒有數據進來,會拋出異常。


import queue

q = queue.Queue()
q.put("d1")
q.put("d2")
q.put("d3")

q.qsize()

print (q.get())
print (q.get())
print (q.get())

print (q.get_nowait())
## 使用get_nowait()來取數據,如果取的數據是空就會拋出異常。

技術分享圖片
可以使用try,except異常來使用get_nowait()來解決獲取空數據的問題;
也可以使用if q.qsize()來判斷==0的話,就是空數據,然後在做下一步操作。


import queue

q = queue.Queue(maxsize=3)  ## 設置隊列中最多可以有多少個數據
q.put("d1")
q.put("d2")
q.put("d3")
q.put("d4") ##因為設置最有能有3個數據,當我們設置第4個數據的時候前三個數據還沒有取出,就會卡主
##可以設置多個線程,變放變取數據,就不會卡主了。

import queue

q = queue.Queue(maxsize=3)
q.put("d1")
q.put("d2")
q.put("d3")
q.put("d4",block=False,timeout=3)
## put也支持block和timeout

Lifo (last in first out 後進先出)

一般場景都是先入先出,後入先出的情況比較少。
賣水果就可以實現後入先出的場景,因為後來的水果比較新鮮,所以就先賣出去的快。

import queue

q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)

print (q.get())
print (q.get())
print (q.get())

執行結果:
3
2
1

PriorityQueue(優先級隊列)

存儲數據時可以設置優先級隊列


import queue

q = queue.PriorityQueue()
q.put((10,"Amy"))
q.put((-1,"Peter"))
q.put((3,"Zhangsan"))
q.put((6,"lisi"))

print (q.get())
print (q.get())
print (q.get())
print (q.get())

執行結果:
(-1, ‘Peter‘)   #優先級最高
(3, ‘Zhangsan‘)
(6, ‘lisi‘)
(10, ‘Amy‘)     #優先級最低
##將數字放在前面就按照數字越小,越優先出
## 也可以按照字母等順序來排列。

生產者消費者模型

假如生產者是視頻服務器,消費者是用戶,用戶消費(看視頻),將請求轉到後臺服務器,生產者處理、提供視頻數據。
但是消費者並不關心你後臺提供了多少臺服務器,所以這種模型解耦比較好。

import threading,time
import queue

q = queue.Queue()

def Producer(name):
    for i in range(10):
        q.put("骨頭%s"%i) ##生產10個骨頭

def Consumer(name):
    while q.qsize() > 0:    #判斷隊列還有數據就循環
        print ("[%s]取到[%s]並且吃了它..."%(name,q.get())) #消費骨頭

p = threading.Thread(target=Producer,args=("LiSi",))
c = threading.Thread(target=Consumer,args=("Dog",))

p.start()
c.start()

執行結果:
[Dog]取到[骨頭0]並且吃了它...
[Dog]取到[骨頭1]並且吃了它...
[Dog]取到[骨頭2]並且吃了它...
[Dog]取到[骨頭3]並且吃了它...
[Dog]取到[骨頭4]並且吃了它...
[Dog]取到[骨頭5]並且吃了它...
[Dog]取到[骨頭6]並且吃了它...
[Dog]取到[骨頭7]並且吃了它...
[Dog]取到[骨頭8]並且吃了它...
[Dog]取到[骨頭9]並且吃了它...
## 生產了10個骨頭,都被dog給吃了。

import threading,time
import queue

q = queue.Queue(maxsize=10) #最大放入十個骨頭

def Producer(name):
    count = 1
    while True: #為了持續性的生產骨頭,這裏使用while。
            q.put("骨頭%s"%count) ##當骨頭超過10個的時候,就卡主了,直到骨頭被取出少於10時循環放骨頭進來
            print ("生產了骨頭%s"%count)
            count += 1
            time.sleep(2)   #兩秒生產1個

def Consumer(name):
    while True:    #這裏設置True,而不是>0,因為剛生產1個被吃掉的話,就不大於0了,dogs就不會再吃骨頭
        print ("[%s]取到[%s]並且吃了它..."%(name,q.get()))
        time.sleep(1)   #這裏設置每秒吃1個骨頭但是因為生產的慢(2秒生產1個),所以就吃的慢。

p = threading.Thread(target=Producer,args=("LiSi",))
c1 = threading.Thread(target=Consumer,args=("Dog1",))
c2 = threading.Thread(target=Consumer,args=("Dog2",))

p.start()
c1.start()
c2.start()

執行結果:
生產了骨頭1
[Dog1]取到[骨頭1]並且吃了它...
生產了骨頭2
[Dog2]取到[骨頭2]並且吃了它...
生產了骨頭3
[Dog1]取到[骨頭3]並且吃了它...
生產了骨頭4
[Dog2]取到[骨頭4]並且吃了它...
生產了骨頭5
[Dog1]取到[骨頭5]並且吃了它...
生產了骨頭6
[Dog2]取到[骨頭6]並且吃了它...
........

def Producer(name):
    count = 1
    while True:
            q.put("骨頭%s"%count)
            print ("生產了骨頭%s"%count)
            count += 1
            time.sleep(0.5)   #現在0.5秒生產1個,相當於1秒生產2個

def Consumer(name):
    while True:
        print ("[%s]取到[%s]並且吃了它..."%(name,q.get()))
        time.sleep(1)   
        ##因為生產的快,兩個線程就吃的快(每個線程每隔1秒吃一個)
        ##兩個線程相當於1秒能吃2個,剛好與生產速度持平;
        ##如果生產過快的話,就是生產大於消費的速度了。

p = threading.Thread(target=Producer,args=("LiSi",))
c1 = threading.Thread(target=Consumer,args=("Dog1",))
c2 = threading.Thread(target=Consumer,args=("Dog2",))

p.start()
c1.start()
c2.start()

執行結果:
生產了骨頭1
[Dog1]取到[骨頭1]並且吃了它...
生產了骨頭2
[Dog2]取到[骨頭2]並且吃了它...
生產了骨頭3
[Dog1]取到[骨頭3]並且吃了它...
生產了骨頭4
[Dog2]取到[骨頭4]並且吃了它...
生產了骨頭5
[Dog1]取到[骨頭5]並且吃了它...

## 生產者消費者模型解決了解耦(生產和消費各幹各的)、排隊的問題(只要生產的資源夠,消費者不需要排隊)。

Python35 events(事件)、隊列