python-进程、线程、协程
·
| 维度 | 进程(Process) | 线程(Thread) | 协程(Coroutine) |
|---|---|---|---|
| 资源占用 | 高(独立内存) | 中(共享进程内存) | 极低(共享线程内存) |
| 创建 / 销毁开销 | 大 | 中 | 极小 |
| 调度者 | 操作系统内核(抢占式) | 操作系统内核(抢占式) | 事件循环(协作式,需主动交出) |
| 并行能力 | 支持多核并行 | 受 GIL 限制,CPU 密集型无法并行 | 单线程执行,不支持并行 |
| 通信成本 | 高(需 IPC 机制) | 低(共享内存,需锁) | 极低(同一线程内直接通信) |
| 适用场景 | CPU 密集型、强隔离任务 | I/O 密集型、轻量并发 | 超高并发 I/O 任务 |
| 每个CPU核心同一时间只能执行一个进程指令 |
Python中同一时刻只有一个线程执行Python字节码 I/O密集型任务:线程数可远大于CPU核数 CPU密集型任务:多线程在CPU任务中性能≈单线程 内存密集型任务: 推荐线程数 = CPU核数 |
黄金法则:在Python中,线程主要用于I/O并发,CPU并行请用进程。
| 数据共享 | 队列、双向管道、共享内存 信号量、事件( Event):用于进程间同步 | 进程的所有内存资源(全局变量、堆内存) 需要锁来保证数据一致 | 该线程的内存空间(全局变量、局部变量等) 同一时间只有一个协程在运行,所以不需要锁 |
GIL 锁:同一时刻只有一个线程能执行 Python 字节码。GIL 并非 Python 语言的特性,而是 CPython 解释器的设计选择
GIL 本质是一把互斥锁(Mutex),任何线程要执行 Python 代码,必须先获取 GIL 锁,执行一段字节码后(默认约 100 次操作)或遇到 I/O 阻塞(如网络请求、文件读写,解释器检测到这是一个可能阻塞的 I/O 请求,先主动释放 GIL)时,会主动释放 GIL,让其他线程有机会获取锁并执行。
CPU 密集型任务为何不适合多线程?
多个线程会频繁抢占 GIL;
切换开销大,效率反而更低;
推荐使用多进程(如 multiprocessing 模块),每个进程有独立 GIL,能真正并行执行。
1.进程(Process)
通过 multiprocessing 模块或 concurrent.futures.ProcessPoolExecutor 创建:
主进程和子进程通过 multiprocessing 底层的管道 / 队列通信,所有传递的参数和结果都必须是可序列化的(pickle 支持)
from multiprocessing import Process
import time
def process_task(name):
print(f"进程 {name} 开始")
time.sleep(2) # 模拟计算
print(f"进程 {name} 结束")
if __name__ == "__main__":
p1 = Process(target=process_task, args=("A",))
p2 = Process(target=process_task, args=("B",))
p1.start()
p2.start()
p1.join() #如果没有 join(),主进程可能会在子进程(p1、p2)还没执行完就提前结束
p2.join()
2. 线程(Thread)
import threading
import time
def thread_task(name):
print(f"线程 {name} 开始")
time.sleep(2) # 模拟I/O等待(释放GIL)
print(f"线程 {name} 结束")
t1 = threading.Thread(target=thread_task, args=("A",))
t2 = threading.Thread(target=thread_task, args=("B",))
t1.start()
t2.start()
t1.join()
t2.join()
3.协程(Coroutine)
import asyncio
# 用 async def 定义协程函数
async def coro_task(name):
print(f"协程 {name} 开始")
await asyncio.sleep(2) # 主动交出控制权,事件循环切换到其他协程
print(f"协程 {name} 结束")
async def main():
# 创建两个协程任务,由事件循环调度
task1 = asyncio.create_task(coro_task("A"))
task2 = asyncio.create_task(coro_task("B"))
await asyncio.gather(task1, task2) # 等待所有协程完成
asyncio.run(main())
更多推荐

所有评论(0)