信号量、条件变量、事件
教程:
信号量(Semaphore)
- 信号量是一把锁,用来控制线程并发数的。信号量是多把锁,同时允许多个线程来更改数据。
- 使用语法:
threading.Semaphore(value)
用以创建信号量对象
acquire()
用以设置线程锁
release()
用以释放线程锁 - 首先,我们需要使用
threading.Semaphore(value)
创建一个信号量的实例,创建实例时,需要指定一个 value 参数 大小,表示内部维护的计数器的大小,默认为 1。接着,在我们对临界资源进行访问的时候,调用acquire()
,此时内置计数器 -1,直到为 0 的时候就阻塞。资源调用完毕后调用release()
,内置计数器 +1,并让某个线程的acquire()
从阻塞变为不阻塞。 - 实例:
import threading
import time
def run(n):
semaphore.acquire() # 设置线程锁
print(n)
time.sleep(3) # 令当前执行的线程暂停2秒后再继续执行
semaphore.release() # 释放线程锁
if __name__ == '__main__':
semaphore = threading.Semaphore(5) # 创建信号量对象,内部维护的计数器的大小设为5,即最多允许5个线程同时运行
for i in range(50):
t = threading.Thread(target=run, args=(i, )) # 创建线程
t.start() # 启动线程活动
条件变量(Condition)
-
条件变量总是与某种类型的锁对象相关联,锁对象可以通过传入获得,或者在缺省的情况下自动创建。当多个条件变量需要共享同一个锁时,传入一个锁很有用。锁是条件对象的一部分,你不必单独地跟踪它。
-
使用语法
threading.Condition()
用以创建条件变量对象
acquire()
用以设置线程锁
release()
用以释放线程锁
notify(n=1)
通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,
最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动
释放Lock。
wait(timeout)
将线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。
wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。
-
实例:
import threading
import time
def run(x):
con.acquire() # 设置线程锁
print(f"我是{x}线程")
# notify(n=1): 通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才
# 能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
con.notify()
print(f"线程{x}挂起")
# wait(timeout)将线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。
con.wait()
time.sleep(1)
print(f"线程{x}再次启动")
con.notify()
con.release() # 释放线程锁
if __name__ == '__main__':
con = threading.Condition() # 创建条件变量对象
for i in range(10):
t = threading.Thread(target=run, args=(i, )) # 创建线程
t.start() # 启动线程活动
事件(Event)
- 事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再阻塞。Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。
- 使用语法:
threading.Event()
用以创建事件对象
set()
用以将内部标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态
clear()
用以将内部标志设为False
is_set
当且仅当内部标志为True时返回True
wait(timeout)
阻塞直到内部标志为真,如果内部标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()或
发生超时
实例:
"""
事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执
行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再
阻塞。Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻
塞状态。
"""
import threading
import time
def car():
while True:
if event.is_set(): # is_set:当且仅当内部标志为True时返回True
print("小车行驶")
else:
print("小车停止")
event.wait() # 阻塞直到内部标志为真,如果内部标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()或发生超时
def set_event():
while True:
event.set() # 将内部标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态
time.sleep(1)
event.clear() # 将内部标志设为False
time.sleep(1)
if __name__ == '__main__':
event = threading.Event() # 创建事件对象
car1 = threading.Thread(target=car) # 创建线程
car1.start() # 启动线程活动
set_e = threading.Thread(target=set_event)
set_e.start()