條件變數同步 有一類線程需要滿足條件之後才能夠繼續執行,Python提供了threading.Condition 對象用於條件變數線程的支持,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、notify()、notifyAll()方法。 lock_con=threading ...
條件變數同步
有一類線程需要滿足條件之後才能夠繼續執行,Python提供了threading.Condition 對象用於條件變數線程的支持,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、notify()、notifyAll()方法。
lock_con=threading.Condition([Lock/Rlock]): 鎖是可選選項,不傳人鎖,對象自動創建一個RLock()。
wait():條件不滿足時調用,線程會釋放鎖併進入等待阻塞;
notify():條件創造後調用,通知等待池激活一個線程;
notifyAll():條件創造後調用,通知等待池激活所有線程。
import threading, time
from random import randint
class Producer(threading.Thread):
def run(self):
global L
while True:
val = randint(0, 100)
print('生產者', self.name, ':Append'+str(val),L)
if lock_con.acquire():
L.append(val)
lock_con.notify()
lock_con.release()
time.sleep(3)
class Consumer(threading.Thread):
def run(self):
global L
while True:
lock_con.acquire()
if len(L) == 0:
lock_con.wait()
print('消費者', self.name, ":Delete" + str(L[0]), L)
del L[0]
lock_con.release()
time.sleep(0.25)
if __name__ == "__main__":
L = []
lock_con = threading.Condition()
threads = []
for i in range(5):
threads.append(Producer())
threads.append(Consumer())
for t in threads:
t.start()
for t in threads:
t.join()
print('---- end ----')
#運行結果:
生產者 Thread-1 :Append63 []
生產者 Thread-2 :Append66 [63]
生產者 Thread-3 :Append20 [63, 66]
生產者 Thread-4 :Append83 [63, 66, 20]
生產者 Thread-5 :Append2 [63, 66, 20, 83]
生產者 Thread-4 :Append26 []
消費者 Thread-6 :Delete26 [26]
生產者 Thread-2 :Append21 []
生產者 Thread-3 :Append71 [21]
生產者 Thread-1 :Append19 [21, 71]
生產者 Thread-5 :Append100 [21, 71, 19]
生產者 Thread-1 :Append96 []
消費者 Thread-6 :Delete96 [96]
........
同步條件
條件同步和條件變數同步差不多意思,只是少了鎖功能,因為條件同步設計於不訪問共用資源的條件環境。event=threading.Event():條件環境對象,初始值 為False;
event.isSet():返回event的狀態值;
event.wait():如果 event.isSet()==False將阻塞線程;
event.set(): 設置event的狀態值為True,所有阻塞池的線程激活進入就緒狀態, 等待操作系統調度;
event.clear():恢復event的狀態值為False。
import threading, time
class Boss(threading.Thread):
def run(self):
print("BOSS: 今晚大家加班")
event.isSet() or event.set()
time.sleep(5)
print("BOSS: 大家可以下班了")
event.isSet() or event.set()
class Worker(threading.Thread):
def run(self):
event.wait()
print("Worker: 唉。。。。")
time.sleep(0.25)
event.clear()
event.wait()
print("Worker: Great!")
if __name__ == "__main__":
event = threading.Event()
threads = []
for i in range(5):
threads.append(Worker())
threads.append(Boss())
for t in threads:
t.start()
for t in threads:
t.join()
#運行結果:
BOSS: 今晚大家加班
Worker: 唉。。。。
Worker: 唉。。。。
Worker: 唉。。。。
Worker: 唉。。。。
Worker: 唉。。。。
BOSS: 大家可以下班了
Worker: Great!
Worker: Great!
Worker: Great!
Worker: Great!
Worker: Great!
列隊
q = Queue.Queue(maxsize = 10) 創建一個“隊列”對象。Queue.Queue類即是一個隊列的同步實現。隊列長度可為無限或者有限。可通過Queue的構造函數的可選參數maxsize來設定隊列長度。如果maxsize小於1就表示隊列長度無限。
q.put()方法在隊尾插入一個項目。put()有兩個參數,第一個item為必需的,為插入項目的值;第二個block為可選參數,預設為1。如果隊列當前為空且block為1,put()方法就使調用線程暫停,直到空出一個數據單元。如果block為0,put方法將引發Full異常。
q.get([block[, timeout]])方法從隊頭刪除並返回一個項目。可選參數為block,預設為True。如果隊列為空且block為True,get()就使調用線程暫停,直至有項目可用。如果隊列為空且block為False,隊列將引發Empty異常,timeout等待時間。
q.qsize() 返回隊列的大小
q.empty() 如果隊列為空,返回True,反之False
q.full() 如果隊列滿了,返回True,反之False
q.full 與 maxsize 大小對應
q.get_nowait() 相當q.get(False)
q.put_nowait(item) 相當q.put(item, False)
q.task_done() 在完成一項工作之後,q.task_done() 函數向任務已經完成的隊列發送一個信號
q.join() 實際上意味著等到隊列為空,再執行別的操作
import queue
d = queue.Queue()
d.put('1')
d.put('2')
d.put('3')
print(d.get())
print(d.get())
print(d.get())
print(d.get())
print(d.get(0))
# 運行結果:
1
2
3
報錯:
queue.Empty
線程操作列表是不安全的。
import threading, time
li = [1, 2, 3, 4, 5]
def pri():
while li:
a = li [-1]
print(a)
time.sleep(1)
try:
li.remove(a)
except:
print('-----', a)
t1 = threading.Thread(target=pri, args=())
t1.start()
t2 = threading.Thread(target=pri, args=())
t2.start()
# 運行結果:
5
5
4
----- 5
4
3
----- 4
3
2
----- 3
2
1
----- 2
1
----- 1
import threading, queue
from time import sleep
from random import randint
class Production(threading.Thread):
def run(self):
while True:
r = randint(0, 100)
q.put(r)
print("生產出來 %s 號包子" %r)
sleep(1)
class Proces(threading.Thread):
def run(self):
while True:
re = q.get()
print('吃掉 %s號包子' %re)
if __name__ == '__main__':
q = queue.Queue(10)
threads = [Production(),Production(),Production(),Proces()]
for t in threads:
t.start()
# 運行結果:
生產出來 94 號包子
生產出來 13 號包子
生產出來 79 號包子
吃掉 94號包子
吃掉 13號包子
吃掉 79號包子
生產出來 43 號包子
吃掉 43號包子
生產出來 32 號包子
吃掉 32號包子
......