信号量也是一把锁,用来控制线程并发数的。
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()