一、线程基础概念:进程与线程的区别、并发与并行的理解、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?我常用的方案有几种:
- 用多进程:每个进程有自己的GIL,互不干扰。适合CPU密集型任务。
- 用C扩展:比如numpy、pandas这些库,底层是C写的,执行时释放GIL。
- 用asyncio:协程方案,单线程内实现高并发,适合IO密集型。
- 用Jython或IronPython:它们没有GIL,但生态不如CPython。
记住这个原则:
- IO密集型 → 多线程或asyncio
- CPU密集型 → 多进程或C扩展
- 混合型 → 多进程+多线程组合
知识体系图
嗯,以上就是线程基础的核心内容。进程和线程的区别要记牢,并发和并行的概念要分清,GIL的影响要心里有数。这些基础打好了,后面学锁、学线程池、学内存泄漏排查才会顺手。
一个小建议:刚开始学多线程时,别急着写复杂代码。先写几个简单的例子,看看单线程和多线程在CPU密集和IO密集场景下的表现差异。亲眼看到GIL的效果,比看十篇文章都管用。
可可精品资料库