1. 线程 vs 进程

进程 Process 线程 Thread
定义 操作系统分配资源的单位 进程内的执行流,CPU 调度的单位
拥有 独立内存、文件、权限、环境变量 只独占栈和寄存器
内存 各进程互相隔离 同进程内所有线程共享
成本 创建/切换毫秒级,重 创建/切换微秒级,轻
数量关系 一个进程 ≥ 1 个线程 线程必须属于某个进程
进程
├── 内存 / 文件 / 权限     ← 进程"拥有"的
└── 线程 × N               ← 线程"执行"的

一句话:进程管「有什么」,线程管「干什么」。进程崩了线程全灭;线程崩了进程没事。

2. 并发 vs 并行

并发 Concurrency 并行 Parallelism
定义 多个任务交替推进,任一时刻只有 1 个在跑 多个任务同时推进,任一时刻有 N 个在跑
前提 不需要多核 必须有多核
判定 CPU时间 ÷ 墙钟时间 ≈ 1 CPU时间 ÷ 墙钟时间 ≈ N
本质 关于结构 关于硬件
并发(1核)          并行(3核)
时刻: 0 1 2 3        时刻: 0 1 2 3
核0   A B A C        核0   A A A A
核1   · · · ·        核1   B B B B
核2   · · · ·        核2   C C C C

一句话:并发是”看起来同时”,并行是”真的同时”。

3. 四者的关系

它们是两个正交维度

  • 线程/进程 = 容器(谁干活、共享什么)
  • 并发/并行 = 时间轴排列(交替还是同时)
        并发(交替)        并行(同时)
线程     ✅ 默认如此         ⚠️ 仅当代码释放 GIL
                            (如 NumPy;纯 Python 被 GIL 锁死)
进程     ✅ 当然可以         ✅ 天然如此(每个进程独占一核)
协程     ✅ 只能这样         ❌ 单线程,永远不并行

GIL是python的Global Intepreter Lock,让一个进程内的所有线程共用一个执行单元,所以 Python 多线程排不成横队,只能排纵队。 也就是说在python里面除非多线程任务能释放GIL(NumPy、PyTorch……),这样线程任务也可以放到多个核上面跑。否则,通过多线程只能在单核上跑实现并发,无法实现并行计算。

4. 并行好理解,那并发有啥好处吗

python代码执行默认是串行的。

代码:step('A', 0.3);  step('B', 0.3);  step('C', 0.3)
     (最普通的写法,没有任何 threading)

   A    |##################                                    |
   B    |                  #################                   |
   C    |                                   ###################|
        +------------------------------------------------------+
         0                                              0.90s

   总耗时 0.90s = 0.3 + 0.3 + 0.3
   三个条形【首尾相接,毫无重叠】

B 必须等 A 执行完才轮到它,C必须等到B执行完后才执行。

Python 代码默认严格串行,一行执行完才走下一行。 但 NumPy 这类 C 扩展库会在内部并行——你的代码串行,库帮你并行。

并发比起串行,好处就一个,就是当你的任务存在等待的时候,并发可以减少等待时间。

任何一个真实任务都能拆成:

  • [计算段] CPU 真的在干活 —— 解析数据、算数、拼字符串
  • [等待段] CPU 闲着,任务在原地等 —— 等网络返回、等磁盘读完、等数据库响应

关键在于:等待段里 CPU 是完全闲置的。 它没在忙别的,就是在干等。

A    |###............                                                 |
B    |               ####............                                 |
C    |                               ####.............                |
D    |                                                ###............ |
     |###------------####------------####-------------###-------------|  ← CPU
     +----------------------------------------------------------------+
      0                                                    2.08s

# = 计算段(CPU 忙)    . = 等待段(CPU 闲着)    - = CPU 完全空闲
CPU 实际忙碌占比 23%

使用并发可以在某个任务等的时候做另一个任务

A    |###########....................................                 |
B    |  ############....................................              |
C    |         ############....................................       |
D    |                ###########.................................... |
     |###########################-------------------------------------|  ← CPU
     +----------------------------------------------------------------+
      0                                                    0.71s

CPU 实际忙碌占比 69%

生活类比:一个人做饭

串行:
烧水 5 分钟 —— 站在灶台边盯着看
水开了,切菜 3 分钟
一共 8 分钟,出一道菜

并发:

烧上水,转身去切菜(3 分钟)
水开了,菜也切好了,下锅
一共 5 分钟,出两道菜

你没有变快。 你还是那个只有一个身体的厨师。你只是不再站着看了。

5. 总结和建议

操作系统
└── 进程(资源隔离,真实并行)
     └── 线程(OS 调度,受 GIL 限制 → 同进程内只能并发)
          └── 协程(Python 事件循环调度,OS 看不见)

CPU 密集 → 往【上】走,用进程抢多核
I/O 密集 → 往【下】走,用协程/线程重叠等待
数值计算 → 跳出这套,直接用 NumPy