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

相关推荐
曦月逸霜9 小时前
Python快速入门——学习笔记(持续更新中~)
笔记·python·学习
喵手9 小时前
Python爬虫实战:采集菜谱网站的“分类/列表页”(例如“家常菜”或“烘焙”频道)数据,构建高可用的美食菜谱数据采集流水线(附CSV导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集菜谱网站数据·家常菜或烘焙频道·构建高可用食谱数据采集系统
喵手9 小时前
Python爬虫实战:硬核解析 Google Chrome 官方更新日志(正则+文本清洗篇)(附 CSV 导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·csv导出·监控谷歌版本发布历史·获取稳定版更新日志
星火开发设计9 小时前
this 指针:指向对象自身的隐含指针
开发语言·数据结构·c++·学习·指针·知识
梵刹古音9 小时前
【C++】构造函数
开发语言·c++
小邓睡不饱耶9 小时前
实战|W餐饮平台智能化菜品推荐方案(含Spark实操+算法选型+完整流程)
python·ai·ai编程·ai写作
独自破碎E9 小时前
【曼哈顿距离】BISHI25 最大 FST 距离
java·开发语言
苏涵.9 小时前
Java三大集合:List、Set、Map
java·开发语言
Amumu121389 小时前
Vue3 Composition API(一)
开发语言·javascript·ecmascript
存在的五月雨9 小时前
Spring Security认证流程
java·开发语言·mysql