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 的多线程不是假的,只是被"限速"了。

相关推荐
Blossom.11821 小时前
知识图谱与大模型融合实战:基于GNN+RAG的企业级智能问答系统
人工智能·python·深度学习·神经网络·微服务·重构·知识图谱
Lvan的前端笔记21 小时前
python:列表推导式(List Comprehension)
开发语言·python·list
李小先21 小时前
supersonic——PARSING阶段
开发语言·python
爱学习的张大21 小时前
如何选择正确版本的CUDA和PyTorch安装
人工智能·pytorch·python
我是华为OD~HR~栗栗呀21 小时前
(华为od)21届-Python面经
java·前端·c++·python·华为od·华为·面试
大、男人21 小时前
FastMCP 高级特性之Background Tasks
人工智能·python·mcp·fastmcp
夕阳下的一片树叶91321 小时前
后端java遇到的问题
java·开发语言
海涛高软21 小时前
Qt中使用QListWidget列表
开发语言·qt
沐知全栈开发21 小时前
MongoDB 删除数据库
开发语言
CodeCraft Studio21 小时前
国产化Excel开发组件Spire.XLS教程:使用Python批量删除Excel分页符
开发语言·python·excel·python开发·spire.xls·excel api库·excel开发组件