一、前言
上一节学习完信号量,接着继续学习有界信号量。
首先看看python官方对有界信号量的描述:
从官方的描述可以看到,release( )方法过多被调用时,就会产生ValueError异常。
二、ValueError异常
2.1、测试有界信号量过多释放是否真的会产生ValueError异常
我在命令行测试了一下,过多的释放的确会产生ValueError:Semaphore released too many times.
三、生产者-消费者模型
本次的代码目的如下:
- 生成者producer每隔3秒时间同步一次消费者1(customer1)与消费者2(customer2)。
- 消费者1(customer1)与消费者2(customer2)每一次被同步都可以运行两次。
3.1、代码
# python3.9
import time
import threading
se1 = threading.BoundedSemaphore(2) # se1信号量的初始数量与上限值是2
se2 = threading.BoundedSemaphore(2) # se2信号量的初始数量与上限值是2
# 消费者1线程函数
def customer1():
global se1
while True:
print("customer1进入阻塞态,等待信号量的释放。")
se1.acquire() # 向se1信号量请求一个信号
print("customer1请求信号量成功,time:%s" % time.perf_counter())
# 消费者2线程函数
def customer2():
global se2
while True:
print("customer2进入阻塞态,等待信号量的释放。")
se2.acquire() # 向se1信号量请求一个信号
print("customer2请求信号量成功,time:%s" % time.perf_counter())
# 生产者线程函数
def producer():
while True:
time.sleep(3) # 休眠3秒钟
# 释放se1两个信号
se1.release()
se1.release()
# 释放se2两个信号
se2.release()
se2.release()
print("producer释放完信号量,其他线程将被同步。time:%s" % time.perf_counter())
# 主线程函数
t1 = threading.Thread(target=producer,name="thread_producer",daemon=True) # 创建producer子线程
t2 = threading.Thread(target=customer1,name="thread_customer1",daemon=True) # 创建cusotmer1子线程
t3 = threading.Thread(target=customer2,name="thread_customer2",daemon=True) # 创建customer2子线程
t1.start() # 启动producer线程
t2.start() # 启动customer1线程
t3.start() # 启动customer2线程
t1.join() # 子线程producer是无限循环的线程,所以主线程需要等待它运行结束
t2.join() # 子线程customer1是无限循环的线程,所以主线程需要等待它运行结束
t3.join() # 子线程customer2是无限循环的线程,所以主线程需要等待它运行结束
print("主线程运行结束!")
if __name__ == "__main__":
main()
3.2、运行的结果
跟上一节的运行结果一样。
我个人认为,尽量避免使用信号量而是使用有界信号量,因为有界信号量的信号量被过多释放时会出现警告ValueError。