Python並發編程:多線程-信號量,Event,定時器
阿新 • • 發佈:2018-07-11
check 使用 __main__ light 分享圖片 %s UNC 設置 main
一 信號量
信號量也是一把鎖,可以指定信號量為5,對比互斥鎖同一時間只能有一個任務搶到鎖去執行,信號量同一時間可以有5個任務拿到鎖去執行,如果說互斥鎖是合租房屋的人去搶一個廁所,那麽信號量就相當於一群路人爭搶公共廁所,公共廁所所有多個坑位,這意味著同一時間可以有多個人上公共廁所,但公共廁所容納的人數是一定的,這便是信號量的大小
from threading import Thread, Semaphore import threading import time def func(): sm.acquire() print(‘%s get sm‘ % threading.current_thread().getName()) time.sleep(3) sm.release() if __name__ == ‘__main__‘: sm = Semaphore(5) for i in range(23): t = Thread(target=func) t.start()
解析
Semaphore管理一個內置的計數器, 每當調用acquire()時內置計數器-1 調用release()時內置計數器+1 計數器不能小於0;當計數器為0時,acquire()將阻塞線程直到其它線程調用rel()
二、Event
線程的一個關鍵特性是每個線程都是獨立運行且狀態不可預測。如果程序中的其它線程需要通過判斷某個線程的狀態來確定自己下一步的操作,這時線程同步問題就會變得非常棘手。為了解決這些問題,我們需要使用threading庫中的Event對象。對象包含一個可由線程設置的信號標誌,它允許線程等待某些事件的發生。在初始情況下,Event對象中的信號標誌被設置為假。如果有線程等待一個Event對象,而這個Event對象的標誌為假,那麽這個線程將會被一直阻塞至標誌為真。一個線程如果將一個Event對象的信號標誌設置為真,它將喚醒所有等待這個Event對象的線程。如果一個線程等待一個已經被設置為真的Event對象,它將忽略這個事件,繼續執行
from threading import Event Event.isSet() # 返回Event的狀態值 Event.wait() # 如果event.isSet()==False將阻塞線程; Event.set() # 設置Event的狀態值為True,所有阻塞池的線程激活進入就緒狀態,等待操作系統調度 Event.clear() # 恢復Event的狀態值為False
例如:有多個工作線程嘗試鏈接MySQL,我們想要在鏈接前確保MySQL服務正常才讓那些工作線程去連接MySQL服務器,如果連接不成功,都會去嘗試重新連接。那麽
from threading import Thread, Event import threading import time, random def conn_mysql(): count = 1 while not event.is_set(): if count > 3: raise TimeoutError(‘鏈接超時‘) print(‘<%s>第%s次嘗試鏈接‘ % (threading.current_thread().getName(), count)) event.wait(0.5) count += 1 print(‘<%s>鏈接成功‘ % threading.current_thread().getName()) def check_mysql(): print(‘\033[45m[%s] 正在檢查mysql\033[0m‘ % threading.current_thread().getName()) time.sleep(random.randint(2, 4)) event.set() if __name__ == ‘__main__‘: event = Event() conn1 = Thread(target=conn_mysql) conn2 = Thread(target=conn_mysql) check = Thread(target=check_mysql) conn1.start() conn2.start() check.start()
三 定時器
定時器,指定n秒後執行某操作
from threading import Timer def hello(): print(‘hello, world‘) t = Timer(1, hello) t.start()
Python並發編程:多線程-信號量,Event,定時器