Semaphore对象维护着一个内部计数器,调用acquire()方法时该计数器减1,调用release()方法时该计数器加1,适用于需要控制特定资源的并发访问线程数量的场合。
调用acquire()方法时,如果计数器已经为0则阻塞当前线程,直到有其他线程调用了release()方法,所以计数器的值永远不会小于0。
Semaphore对象可以调用任意次release()方法,而BoundedSemaphore对象可以保证计数器的值不超过特定的值。
下面的代码使用BoundedSemaphore对象限制特定资源的并发访问线程数量,每次只允许两个线程同时执行。
from threading import Thread, BoundedSemaphore
from time import time, sleep
from random import randrange
def worker(value):
# 线程启动时间
start = time()
with sema:
# 获取资源访问权限的时间
end = time()
# 冒号后面是该线程等待的时间
print(value, ':', end-start)
sleep(randrange(5))
# 同一时刻最多允许2个线程访问特定资源
sema = BoundedSemaphore(2)
# 创建并启动10个线程
for i in range(10):
t= Thread(target=worker, args=(i,))
t.start()
代码的多次运行结果不会完全相同,某次运行结果如下:
0 : 0.0
1 : 0.0
2 : 1.0000569820404053
3 : 3.000171661376953
5 : 4.0002288818359375
4 : 4.0002288818359375
6 : 6.003343343734741
7 : 8.000457525253296
8 : 9.003514766693115
9 : 12.000686407089233
另一次运行结果如下:
0 : 0.0
1 : 0.0
2 : 2.0001144409179688
3 : 2.001114845275879
4 : 2.003114700317383
5 : 3.004171848297119
6 : 3.00517201423645
7 : 4.999285697937012
8 : 5.000285863876343
9 : 7.0054004192352295