信号量也是一把锁,用来控制线程并发数的

  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()

 信号量的主要作用:

  主要用在数据库应用中,比如连接数据库的连接,限制同时连接的数量,如数据库连接池。

posted on 2018-11-06 15:45  老π  阅读(3432)  评论(0编辑  收藏  举报