'''
所謂條件變量,即這種機制是在滿足了特定的條件后,線程才可以訪問相關的數據。
它使用Condition類來完成,由於它也可以像鎖機制那樣用,所以它也有acquire方法和release方法,而且它還有wait,notify,notifyAll方法。
一個簡單的生產消費者模型,通過條件變量的控制產品數量的增減,調用一次生產者產品就是+1,調用一次消費者產品就會-1.
使用 Condition 類來完成,由於它也可以像鎖機制那樣用,所以它也有 acquire 方法和 release 方法,而且它還有
wait, notify, notifyAll 方法。
'''
import threading
import queue, time, random
# 產品類
class Goods:
def __init__(self):
self.count = 0
def add(self, num=1):
self.count += num
def sub(self):
if self.count >= 0:
self.count -= 1
def empty(self):
return self.count <= 0
# 生產者
class Producer(threading.Thread):
def __init__(self, condition, goods, sleeptime=1):
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
# 鎖住資源
cond.acquire()
goods.add()
print("產品數量:", goods.count, "生產者線程")
# 喚醒所有等待的線程 -> 其實就是喚醒消費者進程
cond.notifyAll()
# 解鎖資源
cond.release()
time.sleep(self.sleeptime)
# 消費者
class Consumer(threading.Thread):
def __init__(self, condition, goods, sleeptime=2):
threading.Thread.__init__(self)
self.cond = condition
self.goods = goods
self.sleeptime = sleeptime
def run(self):
cond = self.cond
goods = self.goods
while True:
time.sleep(self.sleeptime)
# 鎖住資源
cond.acquire()
# 如無產品則讓線程等待
while goods.empty():
cond.wait()
goods.sub()
print("產品數量:", goods.count, "消費者線程")
# 解鎖資源
cond.release()
g = Goods() c = threading.Condition() pro = Producer(c, g) pro.start() con = Consumer(c, g) con.start()
'''
event 對象最好單次使用,就是說,你創建一個 event 對象,讓某個線程等待這個對象,
一旦這個對象被設置為真,你就應該丟棄它。盡管可以通過 clear() 方法來重置 event 對
象,但是很難確保安全地清理 event 對象並對它重新賦值。很可能會發生錯過事件、死鎖
或者其他問題(特別是,你無法保證重置 event 對象的代碼會在線程再次等待這個 event對象之前執行)。如果一個線程需要不停地重復使用 event 對象,你最好使用 Condition
對象來代替。下面的代碼使用 Condition 對象實現了一個周期定時器,每當定時器超時的
時候,其他線程都可以監測到:
'''
import threading
import time
class PeriodicTimer:
def __init__(self, interval):
self._interval = interval
self._flag = 0
self._cv = threading.Condition()
def start(self):
t = threading.Thread(target=self.run)
t.daemon = False
t.start()
def run(self):
# Run the timer and notify waiting threads after each interval
while True:
time.sleep(self._interval)
with self._cv:
self._flag ^= 1
self._cv.notify_all()
def wait_for_tick(self):
# wait for the next tick of the timer
with self._cv:
last_flag = self._flag
while last_flag == self._flag:
self._cv.wait()
ptimer = PeriodicTimer(2)
ptimer.start()
def countdown(nticks):
while nticks > 0:
ptimer.wait_for_tick()
print('T-minus', nticks)
nticks -= 1
def countup(last):
n = 0
while n < last:
ptimer.wait_for_tick()
print('Counting', n)
n += 1
threading.Thread(target=countdown, args=(10,)).start()
threading.Thread(target=countup, args=(10,)).start()