python多进程和多线程问题

之前大家经常说python的多线程是假的,这里我们详细分析python的多进程和多线程问题,并进行个总结:

  1. 多进程(Multiprocessing):是"真"的。 是货真价实的操作系统级别的多进程,可以利用多核 CPU 并行计算。
  2. 多线程(Multithreading):也是"真"的,但有"锁"。 它们确实是操作系统的原生线程,不是 模拟出来的"虚拟线程"。但是,由于 Python GIL(全局解释器锁) 的存在,同一时刻只能有一个线程在 CPU 上执行 Python 字节码。

为了彻底明白,我们需要把"虚拟"、"并发"和"并行"这几个概念拆解开来。


1. 多进程 (multiprocessing):真正的人多力量大

当你使用 multiprocessing 库时,Python 会向操作系统申请创建全新的进程。

  • 它的本质:就像你手动打开了 4 个"命令提示符"窗口,分别运行了 4 个 Python 脚本。
  • 资源 :每个进程都有自己独立的 Python 解释器、独立的内存空间、独立的 GIL。
  • 结果 :因为大家都有自己的"地盘"和"解释器",所以它们可以同时在 CPU 的不同核心上跑。
  • 结论 :这是真正的物理并行。如果你有 8 核 CPU,起 8 个进程,CPU 占用率可以直接飙到 100%。

2. 多线程 (threading):真的线程,被"锁"住的手脚

这里是你疑惑的重点。很多人说 Python 线程是"假的",其实这种说法是不准确的。

  • 它的本质 :Python 的 threading 模块调用的是操作系统底层的原生线程接口(比如 Linux 的 pthreads 或 Windows 的线程)。所以从操作系统调度层面看,它们是真线程

  • 为什么像"虚拟"的?(GIL 的锅)

    CPython(我们常用的 Python 版本)在执行代码时,必须持有一把锁,叫 GIL (Global Interpreter Lock)

    • 规则 :任何时候,无论你开了多少个线程,同一个进程内,只能有一个线程持有 GIL 并在 CPU 上运行 Python 代码。

    • 工作方式

      1. 线程 A 拿到锁,跑一会儿。
      2. 线程 A 释放锁(或者被迫暂停)。
      3. 线程 B 抢到锁,跑一会儿。
      4. 线程 B 释放锁。
      • 这一切发生得非常快,看起来像是大家在同时动,但微观上是轮流动的。
  • 结论 :这是并发(Concurrency) ,而不是并行(Parallelism)。对于纯计算任务(比如做数学运算),多线程不仅不会变快,反而因为频繁切换上下文变慢。

3. 既然多线程会被锁住,为什么还要用?

虽然多线程在"算术"上没用,但在等待上非常有用。

场景:I/O 密集型任务(爬虫、读写文件、网络请求)

想象你在做网络爬虫:

  • 单线程 :发送请求 -> 傻等 1 秒服务器响应 -> 处理数据 -> 发送下一个。
  • 多线程
    • 线程 A 发请求 -> 遇到等待(I/O 阻塞) -> 自动释放 GIL 锁
    • 线程 B 拿到锁 -> 发请求 -> 遇到等待 -> 释放锁
    • 线程 C ...

在等待网络数据或磁盘读写时,Python 会释放 GIL。 这时候多线程就体现出优势了:虽然 CPU 还是只能处理一个人的活,但它可以在大家"排队等待"的时候去帮别人干活。

4. 所谓的"虚拟线程"是什么?

既然 Python 的 threading 是系统原生的,那有没有"虚拟"的?

有,那就是 协程(Coroutine) ,比如 Python 的 asyncio 库。

  • 协程:完全由程序(用户态)控制,不需要操作系统参与调度。它是在一个线程里,通过代码逻辑来切换任务。这才是真正意义上的"轻量级/虚拟"并发。

总结:形象的比喻

假设你的 CPU 是一个只有 4 个炉灶的厨房

  1. 多进程(Multiprocessing)

    • 你雇佣了 4 个厨师,每人分到一个炉灶。
    • 效果:4 个人同时炒菜,速度 x4。
    • 代价:你要付 4 份工资,而且他们之间传递调料(数据)很麻烦,因为隔得远。
    • 适用:切肉、剁排骨(CPU 密集型计算)。
  2. 多线程(Threading)

    • 你只雇佣了 1 个厨师,但他要在 4 口锅之间来回跑。
    • 由于 GIL 的存在:这个厨师同一秒钟只能握住一把锅铲。
    • 如果任务是切菜(CPU 计算):他在 4 个案板间跑来跑去切,反而把时间浪费在跑路上了,不如老老实实切完一个再切下一个。
    • 如果任务是炖汤(I/O 等待):锅盖盖上炖汤的时候(等待网络响应),他可以去另一口锅炒菜。这样效率就高了。
    • 适用:炖汤、煮粥(爬虫、文件下载)。
  3. 协程(Asyncio)

    • 还是 1 个厨师,但他经过了精密的时间管理大师训练,知道在那一滴油刚热的时候迅速换手,没有任何多余的动作。

所以,Python 的多线程不是假的,只是被"限速"了。

相关推荐
青春不朽5128 分钟前
Scikit-learn 入门指南
python·机器学习·scikit-learn
rosmis8 分钟前
地铁病害检测系统软件改进记录-2-02
开发语言·前端·javascript
进击的小头17 分钟前
FIR滤波器实战:音频信号降噪
c语言·python·算法·音视频
欧阳x天20 分钟前
STL详解(九)—— stack和queue的模拟实现
开发语言·c++
xqqxqxxq21 分钟前
洛谷算法1-1 模拟与高精度(NOIP经典真题解析)java(持续更新)
java·开发语言·算法
沐知全栈开发27 分钟前
Rust 函数
开发语言
乔江seven27 分钟前
【python轻量级Web框架 Flask 】2 构建稳健 API:集成 MySQL 参数化查询与 DBUtils 连接池
前端·python·mysql·flask·web
2301_810730101 小时前
python第四次作业
数据结构·python·算法
马剑威(威哥爱编程)1 小时前
Libvio.link爬虫技术解析:搞定反爬机制
爬虫·python
zhougl9961 小时前
Java 枚举类(enum)详解
java·开发语言·python