目 录
2.1.1 threading.Semaphore 构造方法
2.1.2 threading.Semaphore 属性和方法
2.2.1 使用 threading.Semaphore 控制最多线程数量
2.2.2 threading.Semaphore 使用 with 减少代码量
3.1 BoundedSemaphore 和 Semaphore 的区别
3.2 threading.BoundedSemaphore 属性和方法
3.3 threading.BoundedSemaphore 使用示范
Python 多线程编程目录
Python 多线程编程-01-threading 模块初识
Python 多线程编程-02-threading 模块-锁的使用
Python 多线程编程-03-threading 模块 - Condition
Python 多线程编程-04-threading 模块 - Event
Python 多线程编程-05-threading 模块 - Semaphore 和 BoundedSemaphore
Python 多线程编程-06-threading 模块 - Timer
Python 多线程编程-07-threading 模块 - Barrier
1. Semaphore 信号量介绍
泛泛的讲,多进程/线程中的信号量机制,可以理解为有二元组(S,Q),S是整形变量,初值为非负数,Q是一个初始状态为空的等待队列,这个机制设计就是为了为了实现进程/线程中同步和互斥关系。
有同学可能没有接触过 Semaphore 信号量的概念,可以简单参考这篇文章。
2.4 CPU管理--信号量和PV操作_一分耕耘一分收获-CSDN博客。虽然这篇文字是针对进程讲的,但是在多线程编程中,信号量的设计意图和使用机制是一样的。
2. threading.Semaphore
threading.Semaphore 可以理解为一个内置的计数器,当调用 acquire 方法时候内置计数器 -1,对应着申请资源;调用 release 方法时候内置计数器+1,对应着释放可用资源。
2.1 threading.Semaphore 属性和方法
2.1.1 threading.Semaphore 构造方法
s=threading.Semaphore(value=1),value 指示信号量的最大计数,默认是1;在代码设计中可以理解为可用资源数目。
2.1.2 threading.Semaphore 属性和方法
序号 | 属性和方法 | 描述 |
1 | acquire(self, blocking=True, timeout=None) | 获得一个信号量,其内置计数器 -1; 如果调用时候不使用参数:如果调用时候计数器大于 0 则 -1 且立刻返回;如果是零时,则阻塞当前线程,等待其他线程调用release() 来释放资源使其大于零。这些是通过适当的交互锁来完成的,因此如果多个acquire() 调用被阻止,release() 将只唤醒其中一个调用。实现可能会随机选择一个,因此哪些被阻塞的线程被唤醒是不可靠的,在这种情况下没有返回值。 如果调用时候使用参数: a) blocking=True 和上面一致,成功时候立刻返回 True b) blocking=False,那么计数器是零时候,不会阻塞,而是立刻返回 False。 c) timeout=n,而不等于 None,那么最多阻塞 n 秒,n 秒内没有获得信号量,则返回 False |
2 | mro() | 内置的 mro 方法,返回类型的方法解析顺序。 |
3 | release(self) | 释放资源,信号量的计数器 +1,如果原来信号量计数器等于0,那么则唤醒一个等待中的线程。 |
2.2 threading.Semaphore 使用示范
2.2.1 使用 threading.Semaphore 控制最多线程数量
下面设计了一个程序,semaphore 设计了最多5个线程可以同时启动,第n个线程 sleep n-1 秒,然后再 release 资源;这样可以看到在第一秒同时启动了 6 个线程(第一个线程立刻释放,所以第六个立刻获得了资源),接下来则是每隔一秒钟有一个线程获得资源。
import threading
import time
s=threading.Semaphore(5)
thread_list=[]
def fun(n):
s.acquire()
print(time.ctime(),"===>",n)
time.sleep(n)
s.release()
for tmp in range(10):
t=threading.Thread(target=fun,args=(tmp,))
thread_list.append(t)
for tmp in range(10):
thread_list[tmp].start()
运行结果如下:
2.2.2 threading.Semaphore 使用 with 减少代码量
使用 with 用法,可以省去 release() 方法,结果是一样的。
s=threading.Semaphore(5)
thread_list=[]
def fun2(n):
with s:
print(time.ctime(),"===>",n)
time.sleep(n)
for tmp in range(10):
t=threading.Thread(target=fun2,args=(tmp,))
thread_list.append(t)
for tmp in range(10):
thread_list[tmp].start()
for tmp in range(10):
thread_list[tmp].join()
print("All done!")
运行结果如下:
3. threading.BoundedSemaphore
3.1 BoundedSemaphore 和 Semaphore 的区别
BoundedSemaphore 和 Semaphore 的区别的区别在于 threading.BoundedSemaphore 会在过多的使用 release() 时候报错 " ValueError: Semaphore released too many times "。
3.2 threading.BoundedSemaphore 属性和方法
threading.BoundedSemaphore 的属性和方法和 threading.Semaphore 非常类似,不再赘述。
3.3 threading.BoundedSemaphore 使用示范
代码设计如下,当对 threading.BoundedSemaphore 重复释放时候,就是会报错。
s=threading.Semaphore(3)
bs=threading.BoundedSemaphore(3)
thread_list=[]
def fun(n):
with s:
print(time.ctime(),"===>",n)
time.sleep(n)
# 即使使用了 with 语句会自动 release,也再显示的释放一次
s.release()
def fun2(n):
with bs:
print(time.ctime(),"===>",n)
time.sleep(n)
bs.release()
for tmp in range(5):
t=threading.Thread(target=fun,args=(tmp,))
thread_list.append(t)
for tmp in range(5):
thread_list[tmp].start()
#
thread_list=[]
time.sleep(6)
for tmp in range(5):
t=threading.Thread(target=fun2,args=(tmp,))
thread_list.append(t)
for tmp in range(5):
thread_list[tmp].start()
print("All done!")
运行结果
'''
要是大家觉得写得还行,麻烦点个赞或者收藏吧,想个博客涨涨人气,非常感谢!
'''