多线程
约 1138 字大约 4 分钟
2025-02-25
Python 中的 多线程(Multithreading) 适用于 I/O 密集型任务(如文件 I/O、网络请求、数据库查询),但由于 GIL(全局解释器锁),不适合 CPU 密集型任务(如数学计算、图像处理)。
基本概念
多线程 是在同一进程中运行多个 线程(Thread),共享内存。它适用于:
- I/O 密集型任务(爬虫、文件 I/O、网络请求)
- GUI 交互(如 Tkinter)
警告
Python 的 GIL 限制: Python 不能让多个线程同时执行 CPU 任务。 适用于 I/O 任务,但 不适合 CPU 计算(推荐 multiprocessing)。
使用
threading 模块的基本用法
Python 使用 threading 模块来创建和管理线程。
import threading
import time
def my_task():
print("线程开始")
time.sleep(2) # 模拟耗时任务
print("线程结束")
# 创建线程
thread = threading.Thread(target=my_task)
# 启动线程
thread.start()
# 等待线程完成
thread.join()
print("主线程结束")
# 输出
# 线程开始
# (等待 2 秒)
# 线程结束
# 主线程结束
- thread.start() 运行线程,thread.join() 等待线程完成。
threading 的并发执行
多个线程可以同时运行,但 GIL 限制 CPU 并行。
import threading
import time
def task(name, delay):
print(f"{name} 开始")
time.sleep(delay)
print(f"{name} 结束")
# 创建多个线程
t1 = threading.Thread(target=task, args=("线程1", 2))
t2 = threading.Thread(target=task, args=("线程2", 3))
# 启动线程
t1.start()
t2.start()
# 等待所有线程完成
t1.join()
t2.join()
print("所有任务完成")
# 输出
# 线程1 开始
# 线程2 开始
# (等待 2 秒)
# 线程1 结束
# (等待 1 秒)
# 线程2 结束
# 所有任务完成
- 多个线程可以同时运行 I/O 任务,提高效率!
ThreadPoolExecutor 线程池
使用 ThreadPoolExecutor 轻松管理多个线程。
import concurrent.futures
import time
def task(name):
print(f"{name} 开始")
time.sleep(2)
print(f"{name} 结束")
# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
executor.submit(task, "任务1")
executor.submit(task, "任务2")
executor.submit(task, "任务3")
- ThreadPoolExecutor(max_workers=3) 控制最多 3 个线程同时运行。
queue.Queue 实现生产者-消费者
queue.Queue 用于线程间通信,避免数据竞争问题。
import threading
import queue
import time
q = queue.Queue()
def producer():
for i in range(5):
time.sleep(1)
q.put(i)
print(f"生产: {i}")
def consumer():
while True:
item = q.get()
print(f"消费: {item}")
time.sleep(2)
q.task_done()
# 创建线程
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer, daemon=True)
t1.start()
t2.start()
t1.join() # 等待生产者完成
q.join() # 等待队列任务完成
- queue.Queue() 避免数据竞争,多个线程可安全访问!
Lock 解决线程安全问题
多个线程访问共享变量时可能引发竞争,需要 Lock 保护。
import threading
count = 0
lock = threading.Lock()
def increment():
global count
for _ in range(100000):
with lock: # 确保只有一个线程修改 count
count += 1
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"最终 count = {count}") # 结果应为 200000
- with lock 确保只有一个线程修改 count,避免竞态条件(Race Condition)。
daemon 守护线程
- 守护线程(Daemon Thread) 会在主线程退出时自动终止。
- 普通线程 需要 join() 等待完成。
import threading
import time
def background_task():
while True:
print("后台任务运行中...")
time.sleep(1)
# 设置为守护线程
t = threading.Thread(target=background_task, daemon=True)
t.start()
time.sleep(3)
print("主线程结束") # 线程自动终止
- 守护线程适用于后台任务,如日志记录、监控等。
threading.Event 实现线程同步
threading.Event 让一个线程等待另一个线程的信号。
import threading
import time
event = threading.Event()
def worker():
print("等待信号...")
event.wait() # 等待信号
print("收到信号,开始工作!")
t = threading.Thread(target=worker)
t.start()
time.sleep(3)
print("发送信号")
event.set() # 发送信号
- event.wait() 让线程等待,event.set() 发送信号!
threading.Timer 设定定时任务
threading.Timer 让任务延迟执行。
import threading
def delayed_task():
print("延迟任务执行")
t = threading.Timer(5, delayed_task) # 5 秒后执行
t.start()
- 适用于定时任务,如定期检查、超时处理等。
总结
方法 | 作用 |
---|---|
threading.Thread | 创建线程 |
thread.start() | 启动线程 |
thread.join() | 等待线程完成 |
ThreadPoolExecutor | 线程池管理 |
queue.Queue | 线程安全的队列 |
threading.Lock | 线程锁,避免竞态条件 |
threading.Event | 线程同步 |
threading.Timer | 延迟任务 |
daemon=True | 守护线程,主线程结束时自动退出 |
多线程 vs 多进程
对比 | 多线程(threading) | 多进程(multiprocessing) |
---|---|---|
适用任务 | I/O 密集型(网络、文件) | CPU 密集型(计算、大数据) |
GIL 影响 | 受 GIL 限制 | 不受 GIL 影响 |
资源占用 | 共享内存 | 独立进程,占用更多资源 |
线程安全 | 需 Lock | 进程间数据隔离 |
- I/O 任务(爬虫、网络请求)→ 多线程
- CPU 任务(数学计算)→ 多进程