Python中的多线程(Multithreading)**技术用于并发执行多个任务,适用于**I/O 密集型操作,如文件读写、网络请求和数据库操作。但由于 GIL(全局解释器锁,Global Interpreter Lock)**的限制,在**CPU 密集型任务(如大规模计算)上,多线程并不能真正实现并行执行,而推荐使用多进程(Multiprocessing)。
1. 线程基础
1.1 什么是线程?
线程(Thread)是程序执行的最小单元,是比进程(Process)更小的执行单元。一个进程可以包含多个线程,这些线程共享相同的内存空间。
1.2 线程的优缺点
✅ 优点
- 更快的上下文切换(比进程快)
- 资源共享(多个线程共享全局变量)
- 适合I/O 密集型任务(如文件读写、网络爬虫)
❌ 缺点
- 受 GIL 限制,不能真正实现 CPU 并行计算
- 线程安全问题(多个线程修改同一变量可能导致数据不一致)
2. Python的多线程实现
Python 提供了 threading 模块来创建和管理线程。
2.1 创建线程
import threadingdef print_numbers():for i in range(5):print(f"子线程: {i}")# 创建线程
t = threading.Thread(target=print_numbers)# 启动线程
t.start()# 主线程继续执行
print("主线程正在运行")
输出示例
主线程正在运行
子线程: 0
子线程: 1
子线程: 2
子线程: 3
子线程: 4
注意:主线程不会等待子线程执行完毕,而是直接向下执行。
2.2 使用 join() 等待线程执行完毕
import threadingdef print_numbers():for i in range(5):print(f"子线程: {i}")t = threading.Thread(target=print_numbers)
t.start()t.join() # 等待子线程执行完毕
print("主线程结束")
输出
子线程: 0
子线程: 1
子线程: 2
子线程: 3
子线程: 4
主线程结束
join()让主线程等待子线程执行完后再继续。
2.3 线程参数
可以向线程传递参数:
import threadingdef print_numbers(name, count):for i in range(count):print(f"{name}: {i}")t = threading.Thread(target=print_numbers, args=("线程1", 3))
t.start()
t.join()
输出
线程1: 0
线程1: 1
线程1: 2
3. 多线程的同步与线程安全
3.1 线程安全问题
多个线程共享全局变量,可能导致数据错误。例如:
import threadingcounter = 0 # 共享变量def increase():global counterfor _ in range(1000000):counter += 1t1 = threading.Thread(target=increase)
t2 = threading.Thread(target=increase)t1.start()
t2.start()t1.join()
t2.join()print("最终 counter 值:", counter)
理论结果:2000000
实际结果:可能小于 2000000(因竞争条件发生)
3.2 线程同步(Lock 互斥锁)
为了解决多个线程同时修改全局变量的问题,使用 threading.Lock() 加锁:
import threadingcounter = 0 # 共享变量
lock = threading.Lock() # 创建锁def increase():global counterfor _ in range(1000000):with lock: # 自动加锁和解锁counter += 1t1 = threading.Thread(target=increase)
t2 = threading.Thread(target=increase)t1.start()
t2.start()t1.join()
t2.join()print("最终 counter 值:", counter)
输出
最终 counter 值: 2000000
🔒
lock.acquire()和lock.release()也可以手动控制,但with lock:更安全。
4. 高级多线程技术
4.1 线程池(ThreadPoolExecutor)
使用 ThreadPoolExecutor 可以更高效地管理多个线程:
from concurrent.futures import ThreadPoolExecutordef task(n):return f"线程执行: {n}"with ThreadPoolExecutor(max_workers=3) as executor:results = executor.map(task, range(5))for res in results:print(res)
输出
线程执行: 0
线程执行: 1
线程执行: 2
线程执行: 3
线程执行: 4
线程池管理多个线程,避免手动创建和回收线程,提升效率。
4.2 线程间通信(Queue)
queue.Queue() 用于在线程间安全地传递数据:
import threading
import queueq = queue.Queue()def producer():for i in range(5):q.put(i)print(f"生产: {i}")def consumer():while not q.empty():item = q.get()print(f"消费: {item}")t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)t1.start()
t1.join() # 等待生产完成t2.start()
t2.join() # 等待消费完成
输出
生产: 0
生产: 1
生产: 2
生产: 3
生产: 4
消费: 0
消费: 1
消费: 2
消费: 3
消费: 4
queue.Queue()让线程同步地交换数据,而不需要Lock。
5. 多线程 vs. 多进程
| 特性 | 多线程(threading) | 多进程(multiprocessing) |
|---|---|---|
| GIL 影响 | 受 GIL 限制,无法利用多核 CPU | 不受 GIL 影响,可以真正并行 |
| 适合任务 | I/O 密集型(如网络请求) | CPU 密集型(如矩阵计算) |
| 内存占用 | 共享内存(开销小) | 独立内存(开销大) |
| 启动速度 | 快 | 慢 |
6. 总结
✅ 适用于 I/O 密集型任务(网络爬虫、文件 I/O)
✅ 使用 threading.Thread() 轻松创建线程
✅ 使用 Lock 确保线程安全
✅ 使用 ThreadPoolExecutor 提高性能
✅ 使用 queue.Queue() 进行线程间通信
如果任务涉及CPU 密集型计算,建议改用 多进程(multiprocessing) 代替多线程。
这样你对 Python 多线程的理解清晰了吗?😃
