from threading import Thread, Semaphore
import time
sem = Semaphore(2) # 打印机最多允许2个线程同时使用
def use_printer(name):
with sem: # 自动获取/释放信号量
print(f"{name}开始打印")
time.sleep(3) # 模拟打印耗时
print(f"{name}打印完成")
# 5个线程竞争打印机
for i in range(5):
Thread(target=use_printer, args=(f"用户{i}",)).start()
# 结果:始终只有2个用户在打印,其余等待
from threading import Thread, Event
import time
event = Event() # 初始标志为False
def student(name):
print(f"{name}准备就绪,等待老师发令")
event.wait() # 阻塞至标志为True
print(f"{name}开始跑步")
# 5个学生准备
for i in range(5):
Thread(target=student, args=(f"学生{i}",)).start()
time.sleep(2) # 老师准备2秒
event.set() # 发令(标志设为True)
# 结果:2秒后所有学生同时开始跑步
五、线程池(concurrent.futures.ThreadPoolExecutor,重点)
1. 核心优势
降低开销:重用线程,避免频繁创建/销毁线程;
提高效率:无需等待线程创建,任务来了直接用空闲线程;
便于管理:控制最大线程数,避免占用过多资源。
2. 2种核心使用方式
(1)submit():提交单个任务,返回Future对象(用result()获取结果)
例如:用线程池计算5个数字的平方:
python复制代码
from concurrent.futures import ThreadPoolExecutor
def square(num):
return num * num
# 创建最多2个线程的线程池
with ThreadPoolExecutor(max_workers=2) as executor:
# 提交5个任务
futures = [executor.submit(square, i) for i in [1,2,3,4,5]]
# 获取结果
for future in futures:
print(f"平方结果:{future.result()}")
# 输出:1、4、9、16、25
(2)map():批量提交任务,直接返回结果迭代器(按输入顺序输出)
例如:用线程池批量下载3个文件(模拟耗时):
python复制代码
from concurrent.futures import ThreadPoolExecutor
import time
def download(file):
time.sleep(1) # 模拟下载耗时
return f"{file}下载完成"
with ThreadPoolExecutor(max_workers=2) as executor:
files = ["视频1.mp4", "图片2.jpg", "文档3.pdf"]
results = executor.map(download, files) # 批量执行
for res in results:
print(res)
# 输出:视频1.mp4下载完成 → 图片2.jpg下载完成 → 文档3.pdf下载完成