一、信号量
概述:信号量是用来控制线程并发数的。每当资源释放递增时(调用acquire)计数器-1,资源消耗时递减(调用release)计数器+1。
调用格式: threading.BoundedSemaphore/Semaphore(value);值默认1
实例:
import threading
import time
def run(n):
semaphore.acquire() #获取信号量并加锁
print(n)
time.sleep(1)
semaphore.release() #解锁
if __name__ == '__main__':
semaphore = threading.Semaphore(5) #一次释放五个线程
for i in range(50):
t = threading.Thread(target=run, args=(i, ))
t.start()
特点:若打印个数不符合所附给的数,会自动补上
二、条件变量
概念:Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。
可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于状态图中的等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。
wait(timeout): 线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError
notify(n=1): 通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
代码如下(示例):
import threading
import time
def run(x):
con.acquire()
print(f'线程{x}')
con.notify()
print(f'线程{x}挂起')
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()
多线程同时:
import threading
import time
def run(x):
con.acquire()
print(f'线程{x}')
con.notify()
print(f'线程{x}挂起')
con.wait()
time.sleep(1)
print(f'线程{x}再次启动')
con.notify()
con.release()
def run2(x):
con.acquire()
print(f'线程{x}')
con.notify()
print(f'线程{x}挂起')
con.wait()
time.sleep(1)
print(f'线程{x}再次启动')
con.notify()
con.release()
if __name__ == '__main__':
con = threading.Condition()
t1 = threading.Thread(target=run, args=(1, ))
t1.start()
t2=threading.Thread(target=run2, args=(2, ))
t2.start()
三、事件
import threading
import time
def car(): # 设置一个函数判断事件的发生
while True:
if event.is_set(): # 表示事件正在发生
print('小车行驶')
else:
print('小车停止')
event.wait() # 等待事件
def set_event(): #设置一个事件函数
while True:
event.set() # 运行事件
time.sleep(1)
event.clear() #清除事件
time.sleep(3)
if __name__ == '__main__':
event = threading.Event() #创建事件
car1 = threading.Thread(target=car) #多线程运行,同时开始事件并同时判断事件是否发生
car1.start()
set_e = threading.Thread(target=set_event)
set_e.start()