一、线程基础概念:进程与线程的区别、并发与并行的理解、Python中的GIL全局解释器锁

1.1 进程与线程:到底差在哪?

很多初学者问我,进程和线程到底有什么区别?我一般会打个比方:进程就像一家餐厅,线程就是里面的厨师。

餐厅有自己的场地、厨房、食材(这就是进程的资源)。厨师们共享厨房和食材,各自炒菜(这就是线程的工作方式)。如果一家餐厅倒闭了,里面的厨师自然也没活干——进程挂了,线程全完蛋。

但反过来,一个厨师切到手了,只是他那一锅菜受影响,餐厅还能继续营业——线程挂了,进程不一定挂。不过要是这个厨师把厨房点着了……嗯,那整个餐厅都得关门。

核心区别总结:

  • 资源开销:进程是重量级的,创建进程需要分配独立的内存空间;线程是轻量级的,共享进程的内存
  • 通信方式:进程间通信(IPC)需要管道、队列、共享内存等机制;线程间直接读写共享变量就行
  • 隔离性:进程之间互相隔离,一个进程崩了不影响其他进程;线程崩了可能拖垮整个进程
  • 切换成本:进程切换需要切换页表、刷新TLB,成本高;线程切换只需保存寄存器,成本低得多

我在项目中遇到过一个问题:用多进程处理大量数据,结果内存直接爆了。后来改成多线程,内存占用降了60%,但又要处理线程安全问题。说白了,没有银弹,得根据场景选。

1.2 并发与并行:你以为是一回事?

这两个词经常被混用,但本质完全不同。我习惯这么理解:

  • 并发(Concurrency):一个人同时处理多件事,但同一时刻只做一件。比如你一边写代码一边听歌,其实是在快速切换注意力。
  • 并行(Parallelism):多个人同时做不同的事。比如你写代码,你同事写文档,同时进行。

用计算机的话说:并发是逻辑上的同时,并行是物理上的同时。

单核CPU只能实现并发,不能实现并行。多核CPU才能做到真正的并行。你想想看,如果你的电脑是4核8线程,那最多只能同时跑8个线程,其他线程都在排队等着。

我的经验:写并发程序时,别假设代码会同时执行。我曾经写过一个定时任务,以为两个任务会并行跑,结果在单核服务器上它们其实是交替执行的,导致一个任务超时影响了另一个。后来我加了超时隔离才解决。

1.3 Python的GIL:绕不开的坎

说到Python多线程,就不得不提GIL(Global Interpreter Lock,全局解释器锁)。很多新手一听到GIL就慌了,觉得Python多线程是废物。其实没那么夸张。

GIL是什么?简单说,Python解释器里有一把大锁,保证同一时刻只有一个线程在执行Python字节码。为什么要有这把锁?因为Python的内存管理不是线程安全的,如果不加锁,多个线程同时操作引用计数,内存分分钟崩给你看。

我刚开始学Python多线程时,写了个计算密集型的程序,开了8个线程,结果比单线程还慢。当时我就懵了——说好的多线程加速呢?后来查资料才知道是GIL搞的鬼。

避坑指南:我曾经在数据处理项目里用了多线程,以为能加速,结果CPU占用率只有100%(单核满载),其他核心都在摸鱼。后来改成多进程,CPU直接飙到400%,速度提升了3倍多。

那GIL到底影响什么?

  • CPU密集型任务:多线程基本没用,甚至更慢。因为线程切换有开销,但计算还是只能一个一个来。
  • IO密集型任务:多线程很有用。因为线程在等待IO(比如网络请求、文件读写)时会释放GIL,其他线程可以趁机执行。

举个例子:

# CPU密集型:多线程反而慢
import threading
import time

def count_down(n):
    while n > 0:
        n -= 1

# 单线程
start = time.time()
count_down(50000000)
print(f"单线程耗时: {time.time() - start}")

# 多线程
start = time.time()
t1 = threading.Thread(target=count_down, args=(25000000,))
t2 = threading.Thread(target=count_down, args=(25000000,))
t1.start()
t2.start()
t1.join()
t2.join()
print(f"多线程耗时: {time.time() - start}")

跑一下你会发现,多线程版本反而更慢。这就是GIL的“功劳”。

那怎么绕过GIL?我常用的方案有几种:

  1. 用多进程:每个进程有自己的GIL,互不干扰。适合CPU密集型任务。
  2. 用C扩展:比如numpy、pandas这些库,底层是C写的,执行时释放GIL。
  3. 用asyncio:协程方案,单线程内实现高并发,适合IO密集型。
  4. 用Jython或IronPython:它们没有GIL,但生态不如CPython。

记住这个原则:

  • IO密集型 → 多线程或asyncio
  • CPU密集型 → 多进程或C扩展
  • 混合型 → 多进程+多线程组合

知识体系图

线程基础概念知识体系 进程 vs 线程 并发 vs 并行 GIL全局解释器锁 进程:独立内存、高开销、强隔离 线程:共享内存、低开销、弱隔离 IPC vs 共享变量通信 并发:逻辑同时,物理交替 并行:物理同时,多核必备 单核只能并发,多核才能并行 同一时刻只有一个线程执行 CPU密集:多线程无效 IO密集:多线程有效 解决方案:多进程 | C扩展 | asyncio | Jython 选择哪种方案,取决于你的任务类型和性能要求

嗯,以上就是线程基础的核心内容。进程和线程的区别要记牢,并发和并行的概念要分清,GIL的影响要心里有数。这些基础打好了,后面学锁、学线程池、学内存泄漏排查才会顺手。

一个小建议:刚开始学多线程时,别急着写复杂代码。先写几个简单的例子,看看单线程和多线程在CPU密集和IO密集场景下的表现差异。亲眼看到GIL的效果,比看十篇文章都管用。

可可精品资料库