1. 程式人生 > >PYTHON——多執行緒:訊號量(Semaphore)

PYTHON——多執行緒:訊號量(Semaphore)

  訊號量也是一把鎖,用來控制執行緒併發數的

  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,Thread
from 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()