Python35 events(事件)、隊列
阿新 • • 發佈:2018-03-16
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(事件)、隊列