PYTHON——多執行緒:訊號量(Semaphore)
阿新 • • 發佈:2018-11-06
訊號量也是一把鎖,用來控制執行緒併發數的。
BoundedSemaphore或Semaphore管理一個內建的計數 器,每當呼叫acquire()時-1,呼叫release()時+1。
計數器不能小於0,當計數器為 0時,acquire()將阻塞執行緒至同步鎖定狀態,直到其他執行緒呼叫release()。(類似於停車位的概念)
BoundedSemaphore與Semaphore的唯一區別在於前者將在呼叫release()時檢查計數 器的值是否超過了計數器的初始值,如果超過了將丟擲一個異常。
例項1:
import threading,time class myThread(threading.Thread): def run(self): if semaphore.acquire(): print(self.name) time.sleep(5) semaphore.release() if __name__=="__main__": semaphore=threading.Semaphore(5) thrs=[] for i in range(100): thrs.append(myThread())for t in thrs: t.start()
例項2:
本例通過訊號量(Semaphore)和執行緒鎖模擬了一個糖果機補充糖果和使用者取走糖果的過程,糖果機有5個槽,如果發現某個槽沒有糖果了,則需要補充新的糖果。當5個槽都裝滿時,無法補充新的糖果。如果5個槽都是空的,則使用者無法購買糖果。為了便於說明問題,本例假設顧客一次會購買整個槽的糖果,每次補充整個槽的糖果。
from atexit import register from random import randrange from threading import BoundedSemaphore,Lock,Threadfrom time import sleep,ctime #建立執行緒鎖 lock= Lock() #定義糖果的槽數,也是訊號量計數器的最大值 MAX=5 #建立訊號量物件,並指定計數器的最大值 candytray = BoundedSemaphore(MAX) #給糖果機的槽補充新的糖果(每次只補充一個槽) def refill(): #獲取執行緒鎖,將補充的糖果的操作變成原子操作 lock.acquire() print('重新新增糖果......',end=' ') try: #為糖果機的槽補充糖果(計數器+1) candytray.release() except ValueError: print('糖果機都滿了,無法新增') else: print('成功新增糖果') lock.release() #顧客購買糖果 def buy(): lock.acquire() print('購買糖果......',end=' ') #顧客購買糖果(計數器-1),如果購買失敗(5個槽都沒有糖果了),返回False if candytray.acquire(False): print('成功購買糖果') else: print('糖果機為空,無法購買糖果') lock.release() def producer(loops): for i in range(loops): refill() sleep(randrange(3)) #產生多個購買糖果的動作 def consumer(loops): for i in range(loops): buy() sleep((randrange(3))) def main(): print('開始:',ctime()) nloops = randrange(2,6) print('糖果機共有%d個槽!' % MAX) #開始一個執行緒,用於執行consumer函式 Thread(target=consumer,args=(randrange(nloops,nloops+MAX+2),)).start() #開始一個執行緒,用於執行producer函式。 Thread(target=producer,args=(nloops,)).start() @register def exit(): print('程式執行完畢:',ctime()) if __name__ == '__main__': main()