threading 是 Python 中用于实现多线程编程的标准库模块,它建立在 _thread 模块之上,提供了更高级的线程管理接口。
基本概念
线程 vs 进程
- 进程:操作系统分配资源的基本单位,每个进程有独立的内存空间
- 线程:进程内的执行单元,共享进程的内存空间,创建和切换开销更小
GIL(全局解释器锁)
Python 的 GIL 限制了同一时刻只能有一个线程执行 Python 字节码,因此:
- I/O 密集型任务:多线程能有效提高效率
- CPU 密集型任务:多线程可能无法提高性能,应考虑多进程
基本用法
创建线程
import threading
import time
# 方法1:继承 Thread 类
class MyThread(threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f"线程 {self.name} 开始")
time.sleep(2)
print(f"线程 {self.name} 结束")
# 方法2:使用函数
def worker(name):
print(f"线程 {name} 开始")
time.sleep(2)
print(f"线程 {name} 结束")
# 创建线程
thread1 = MyThread("Thread-1")
thread2 = threading.Thread(target=worker, args=("Thread-2",))
# 启动线程
thread1.start()
thread2.start()
# 等待线程结束
thread1.join()
thread2.join()
print("所有线程执行完毕")线程同步
1. Lock(锁)
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock: # 自动获取和释放锁
counter += 1
threads = []
for i in range(5):
thread = threading.Thread(target=increment)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(f"最终计数器值: {counter}") # 应该是 5000002. RLock(可重入锁)
# RLock 允许同一个线程多次获取锁
rlock = threading.RLock()
def recursive_function(count):
with rlock:
if count > 0:
print(f"获取锁,计数: {count}")
recursive_function(count - 1)
thread = threading.Thread(target=recursive_function, args=(5,))
thread.start()
thread.join()3. Condition(条件变量)
import threading
import time
# 生产者-消费者示例
items = []
condition = threading.Condition()
def consumer():
with condition:
while not items:
print("消费者等待...")
condition.wait() # 释放锁并等待
item = items.pop()
print(f"消费: {item}")
def producer():
with condition:
items.append("产品")
print("生产了一个产品")
condition.notify() # 通知等待的消费者
# 创建线程
consumer_thread = threading.Thread(target=consumer)
producer_thread = threading.Thread(target=producer)
consumer_thread.start()
time.sleep(1) # 确保消费者先等待
producer_thread.start()
consumer_thread.join()
producer_thread.join()4. Semaphore(信号量)
# 限制同时访问资源的线程数量
semaphore = threading.Semaphore(3) # 最多3个线程同时访问
def access_resource(thread_id):
with semaphore:
print(f"线程 {thread_id} 访问资源")
time.sleep(2)
print(f"线程 {thread_id} 释放资源")
threads = []
for i in range(10):
thread = threading.Thread(target=access_resource, args=(i,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()5. Event(事件)
# 线程间通信的简单机制
event = threading.Event()
def waiter():
print("等待事件发生...")
event.wait() # 阻塞直到事件被设置
print("事件已发生,继续执行")
def setter():
time.sleep(2)
print("设置事件")
event.set() # 设置事件,唤醒所有等待的线程
t1 = threading.Thread(target=waiter)
t2 = threading.Thread(target=setter)
t1.start()
t2.start()
t1.join()
t2.join()线程局部数据
# 每个线程有自己独立的数据副本
local_data = threading.local()
def show_data():
try:
print(f"线程 {threading.current_thread().name}: {local_data.value}")
except AttributeError:
print(f"线程 {threading.current_thread().name}: 没有数据")
def set_data(value):
local_data.value = value
show_data()
thread1 = threading.Thread(target=set_data, args=("线程1的数据",), name="Thread-1")
thread2 = threading.Thread(target=set_data, args=("线程2的数据",), name="Thread-2")
thread1.start()
thread2.start()
thread1.join()
thread2.join()定时器线程
def hello():
print("Hello, world!")
# 5秒后执行hello函数
timer = threading.Timer(5.0, hello)
timer.start()
print("定时器已启动,等待5秒...")线程池(Python 3.2+)
from concurrent.futures import ThreadPoolExecutor
import time
def task(name, duration):
print(f"任务 {name} 开始")
time.sleep(duration)
print(f"任务 {name} 完成")
return f"任务 {name} 结果"
# 使用线程池
with ThreadPoolExecutor(max_workers=3) as executor:
# 提交任务
future1 = executor.submit(task, "A", 2)
future2 = executor.submit(task, "B", 1)
future3 = executor.submit(task, "C", 3)
# 获取结果
print(future1.result())
print(future2.result())
print(future3.result())守护线程
def daemon_worker():
while True:
print("守护线程运行中...")
time.sleep(1)
def normal_worker():
print("普通线程开始")
time.sleep(3)
print("普通线程结束")
# 创建守护线程
daemon_thread = threading.Thread(target=daemon_worker)
daemon_thread.daemon = True # 设置为守护线程
daemon_thread.start()
# 创建普通线程
normal_thread = threading.Thread(target=normal_worker)
normal_thread.start()
normal_thread.join()
print("主程序结束") # 守护线程会随主程序结束而终止最佳实践
- 避免使用全局变量:使用线程局部数据或传递参数
- 合理使用锁:尽量减少锁的持有时间
- 使用线程安全的数据结构:如
queue.Queue - 考虑使用线程池:避免频繁创建销毁线程的开销
- 处理异常:线程中的异常不会传播到主线程
# 线程异常处理示例
def safe_worker():
try:
# 可能出错的代码
raise ValueError("线程内部错误")
except Exception as e:
print(f"线程捕获到异常: {e}")
thread = threading.Thread(target=safe_worker)
thread.start()
thread.join()threading 模块为 Python 提供了强大的多线程编程能力,但在使用时需要注意线程安全和 GIL 的限制。
















