信号量也是一把锁,用来控制线程并发数的。
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(): #每次最大5个线程运行,具体哪些线程运行,系统自动调配。
print(self.name)
time.sleep(3)
semaphore.release()
if __name__=="__main__":
semaphore=threading.Semaphore(5) #每次最大5个线程运行
thrs=[]
for i in range(100): #创建了100个线程。
thrs.append(myThread())
for t in thrs:
t.start() #启动了100个线程。
实例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()
信号量的主要作用:
主要用在数据库应用中,比如连接数据库的连接,限制同时连接的数量,如数据库连接池。