一、核心概念与区别

先用通俗的比喻帮你理解:

  • 进程:相当于一个独立的 “工厂”,有自己的厂房、设备和资源,工厂之间互不干扰。
  • 线程:是工厂里的 “工人”,共享工厂的资源(比如原料),多个工人可以同时干活,但同一时间工厂里的某些关键设备(GIL 锁)只能被一个工人使用。
  • 协程:是工人手里的 “任务清单”,工人可以暂停当前清单去处理另一个,切换成本极低,完全由工人自己控制(用户态),而非工厂管理层(操作系统)。
1. 核心区别对比表
特性 进程 线程 协程
资源占用 大(独立内存空间) 小(共享进程内存) 极小(用户态切换)
切换成本 高(操作系统内核态切换) 中(内核态切换,受 GIL 影响) 极低(用户态切换)
数据共享 复杂(需 IPC:管道 / 队列等) 简单(共享进程内存,需加锁) 极简单(共享同一线程内存)
并行能力(多核) 支持(真正并行) Python 中不支持(GIL 限制) 不支持(单线程内切换)
创建 / 销毁开销 极小
调度者 操作系统 操作系统 程序员 / 框架(如 asyncio)
2. 关键补充(Python 特有的 GIL 锁)

Python 的全局解释器锁(GIL) 是线程的 “痛点”:同一进程中,同一时间只能有一个线程执行 Python 字节码。这意味着:

  • Python 的线程无法利用多核 CPU 实现真正的并行(仅能并发);
  • 线程适合 I/O 密集型任务(如网络请求、文件读写),而非 CPU 密集型任务。

二、各自的应用场景

1. 进程(multiprocessing 模块)

适用场景

  • CPU 密集型任务(充分利用多核):比如大数据计算、视频编解码、数学建模、数据加密 / 解密;
  • 需要隔离资源的场景:比如多个独立的任务,互不干扰,崩溃不影响主进程;
  • 示例代码(多进程计算):

python

运行

from multiprocessing import Pool
import time

# 模拟CPU密集型任务:计算平方
def cpu_intensive_task(n):
    time.sleep(1)  # 模拟计算耗时
    return n * n

if __name__ == "__main__":
    start = time.time()
    # 创建4个进程的进程池(适配4核CPU)
    with Pool(processes=4) as pool:
        results = pool.map(cpu_intensive_task, [1,2,3,4])
    end = time.time()
    print(f"结果:{results},耗时:{end-start:.2f}秒")  # 耗时约1秒(并行)
2. 线程(threading 模块)

适用场景

  • I/O 密集型任务(等待外部资源):比如网络请求、数据库查询、文件读写;
  • 轻量级并发(无需多核):比如 GUI 程序的后台任务(避免界面卡死);
  • 示例代码(多线程下载):

python

运行

import threading
import time
import requests

# 模拟I/O密集型任务:下载网页
def io_intensive_task(url):
    response = requests.get(url)
    print(f"获取{url}:状态码{response.status_code}")

if __name__ == "__main__":
    start = time.time()
    urls = ["https://www.baidu.com", "https://www.qq.com", "https://www.163.com"]
    threads = []
    # 创建多个线程
    for url in urls:
        t = threading.Thread(target=io_intensive_task, args=(url,))
        threads.append(t)
        t.start()
    # 等待所有线程完成
    for t in threads:
        t.join()
    end = time.time()
    print(f"耗时:{end-start:.2f}秒")  # 耗时约0.5秒(并发等待网络)
3. 协程(asyncio 模块)

适用场景

  • 超高并发的 I/O 密集型任务:比如爬虫、微服务接口、消息队列消费;
  • 要求极致性能的单线程并发:比如每秒处理上万次网络请求;
  • 示例代码(协程并发请求):

python

运行

import asyncio
import aiohttp
import time

# 异步I/O任务:请求网页
async def coro_task(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print(f"获取{url}:状态码{response.status}")

async def main():
    start = time.time()
    urls = ["https://www.baidu.com", "https://www.qq.com", "https://www.163.com"]
    # 创建任务列表并并发执行
    tasks = [coro_task(url) for url in urls]
    await asyncio.gather(*tasks)
    end = time.time()
    print(f"耗时:{end-start:.2f}秒")  # 耗时比线程更少(无内核态切换)

if __name__ == "__main__":
    asyncio.run(main())

三、选型建议(快速决策)

  1. 做计算(CPU 密集)→ 用进程
  2. 做简单的等待(I/O 密集,并发量低)→ 用线程
  3. 做超高并发的等待(I/O 密集,并发量高)→ 用协程
  4. 混合场景:比如 “计算 + 网络”→ 进程 + 协程(进程利用多核,协程处理每个进程内的高并发 I/O)。

总结

  1. 进程:资源隔离、多核并行、开销大,适合 CPU 密集型任务;
  2. 线程:共享资源、GIL 限制、开销中,适合低并发 I/O 密集型任务;
  3. 协程:用户态切换、无 GIL、开销极小,适合超高并发 I/O 密集型任务;核心原则:CPU 密集选进程,I/O 密集看并发量(低→线程,高→协程)。

更多推荐