Event
事件對象管理一個內部標志,通過set()
方法將其設置為True
,並使用clear()
方法將其設置為False
。wait()
方法阻塞,直到標志為True
。該標志初始為False
。
方法:
is_set()
當且僅當內部標志為True
時返回True
。
set()
將內部標志設置為True
。所有等待它成為True
的線程都被喚醒。當標志保持在True
的狀態時,線程調用wait()
是不會阻塞的。
clear()
將內部標志重置為False
。隨后,調用wait()
的線程將阻塞,直到另一個線程調用set()
將內部標志重新設置為True
。
wait(timeout=None)
阻塞直到內部標志為真。如果內部標志在wait()
方法調用時為True
,則立即返回。否則,則阻塞,直到另一個線程調用set()
將標志設置為True
,或發生超時。
該方法總是返回True
,除非設置了timeout
並發生超時。
生產者與消費之--Event版
# -*- coding:utf-8 -*-
import threading
import time
import queue
event = threading.Event()
goods = queue.Queue(5)
num = 0
class Producer(threading.Thread):
def run(self):
global num
while True:
if goods.empty():
event.clear()
for _ in range(5):
goods.put('商品-' + str(num))
print('生產了商品-{0}.'.format(str(num)))
num += 1
time.sleep(1)
event.set()
class Customer(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.money = 7
def run(self):
while self.money:
event.wait()
self.money -= 1
print('{0} 買了一個{1}.'.format(
threading.current_thread().name, goods.get()))
time.sleep(1)
print('{0}沒錢了,回家.'.format(threading.current_thread().name))
if __name__ == '__main__':
p = Producer(daemon=True)
c1 = Customer(name='Alice')
c2 = Customer(name='Bob')
c2.start()
p.start()
c1.start()
c1.join()
c2.join()
運行結果:
生產了商品-0.
生產了商品-1.
生產了商品-2.
生產了商品-3.
生產了商品-4.
Alice 買了一個商品-0.
Bob 買了一個商品-1.
Alice 買了一個商品-2.
Bob 買了一個商品-3.
Alice 買了一個商品-4.
生產了商品-5.
生產了商品-6.
生產了商品-7.
生產了商品-8.
生產了商品-9.
Alice 買了一個商品-5.
Bob 買了一個商品-6.
Alice 買了一個商品-7.
Bob 買了一個商品-8.
生產了商品-10.
Alice 買了一個商品-9.
生產了商品-11.
生產了商品-12.
生產了商品-13.
生產了商品-14.
Alice 買了一個商品-10.
Bob 買了一個商品-11.
Alice沒錢了,回家.
Bob 買了一個商品-12.
Bob 買了一個商品-13.
Bob沒錢了,回家.
這里會出現一種特殊情況,當消費者線程較多時會大量出現:
生產了商品-0.
生產了商品-1.
生產了商品-2.
生產了商品-3.
生產了商品-4.
Bob 買了一個商品-0.
Alice 買了一個商品-1.
Bob 買了一個商品-2.
Alice 買了一個商品-3.
Bob 買了一個商品-4.
生產了商品-5. # !!!!!
Alice 買了一個商品-5. # !!!!!
生產了商品-6.
生產了商品-7.
生產了商品-8.
生產了商品-9.
Bob 買了一個商品-6.
Alice 買了一個商品-7.
Alice 買了一個商品-8.
Bob 買了一個商品-9.
生產了商品-10.
生產了商品-11.
生產了商品-12.
生產了商品-13.
生產了商品-14.
Alice 買了一個商品-10.
Bob 買了一個商品-11.
Bob 買了一個商品-12.
Alice 買了一個商品-13.
Bob沒錢了,回家.
Alice沒錢了,回家.
這是因為生產者在輪詢檢查商品是否為空會有很小的延遲,在這個延遲中有消費者線程正好跑過了wait()
方法,而阻塞在了商品獲取這里(商品使用了隊列,隊列是線程安全的,當隊列為空時,get()方法會阻塞),所以當生產者開始執行的時候,這個消費者因為商品隊列里有數據就被立即喚醒了。