【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系

文章目录


C++ 与 Python:类型、编译器/解释器与 CPU 的关系

一、问题从哪来:为什么 trellis2 要 Pyhon 和 C++ 结合用?

在工程里常见一种分工:性能关键路径用 C++ (例如网格扫描、体素哈希、矩阵求解),胶水、调参、训练用 Python

同一套"密集循环 + 大量内存访问"的逻辑,用 Python 写往往会慢一个数量级以上。

原因可以归结为:类型在何时、以何种方式被确定,决定了代码最终如何变成 CPU 能执行的形式。


二、CPU 只认什么

CPU 不认"C++"或"Python",也不认"整数""浮点数"这些概念。

它只执行机器码 :一串二进制指令,例如"从某地址读 8 字节""做一次浮点加""把结果写回某地址""根据条件跳转"。

任何高级语言要跑起来,最终都必须变成这样一串指令;差别在于:谁、在什么时候、以什么方式完成这种转换。


三、类型扮演的角色

类型是语言层面的约定:规定"一块数据是什么、占多少空间、能参与哪些运算"。

  • C++ 里,变量在写代码时就有明确类型(intfloatEigen::Vector3f 等),且一般不会在运行时变成别的类型。
  • Python 里,同一个名字可以先指向一个整数,再指向一个列表,再指向任意对象;类型是运行时附着在对象上的属性。

因此:

  • 类型越早、越固定 ,就越容易在编译时把"人类写的运算"直接对应到某几条 CPU 指令。
  • 类型越晚、越不固定 ,就只能在运行时再查"当前是什么类型、该调用哪段实现",无法在编译时生成"一步到位"的机器码。

四、C++:编译时定类型,一次生成机器码

  • 源码里每个变量都有静态类型(显式写出或由编译器推导,但编译后固定)。
  • 编译器在编译时就知道:某次加法是"两个 float 相加",某次访问是"从某结构体偏移 8 字节读 4 个 int"。
  • 于是编译器可以直接生成对应的机器指令序列(用哪条 CPU 指令、数据放在哪、如何寻址),写入可执行文件。
  • 运行时 :CPU 加载这段机器码,按指令执行即可,不再需要查类型、选实现
  • 类型在 C++ 里的作用,可以理解为:给编译器足够的信息,让它一次性把"带类型的运算"翻译成 CPU 指令

五、Python:运行时定类型,解释器每次"查表"

  • 源码里不写变量类型,同一个名字在不同时刻可以指向不同类型的对象。
  • 因此编译时 无法确定"这个 + 是整数加、浮点加还是列表拼接",编译器(严格说是 Python 的"编译"前端)只能生成字节码(一种中间表示),而不是最终给 CPU 的机器码。
  • 运行时解释器 (如 CPython)执行字节码。每次遇到一次运算(例如 a + b),解释器会:
    • 查看当前 ab 指向的对象的类型;
    • 根据类型查找对应的实现(例如 int__add__);
    • 调用那段实现(通常是用 C 写的,最终会变成 CPU 指令)。
  • 所以:类型在 Python 里是运行时的属性,每次运算都可能涉及"查类型、选实现";CPU 直接跑的是解释器本身的机器码,而"Python 的加法"要经过解释器这一层间接才能变成 CPU 上的计算。

六、编译器 vs 解释器:谁在"对接"CPU?

角色 在 C++ 中 在 Python 中(以 CPython 为例)
类型 编译时确定、固定 运行时确定、可变
谁做翻译 编译器 解释器(+ 少量 JIT 可选)
何时翻译 编译时,一次性 运行时,按条解释 / 按需 JIT
产出 可直接执行的机器码 字节码;真正执行的是解释器的机器码
与 CPU 的关系 编译器产出 → CPU 直接执行 解释器(机器码)在 CPU 上跑,解释器再驱动"Python 运算"

可以简单记:

  • C++:类型 → 编译器 → 机器码 → CPU。
  • Python:类型(运行时)→ 解释器查类型、调实现 → 内部 C 等实现转为机器码 → CPU。

七、为什么"类型少且确定"就容易快?

  • C++:类型少且确定,编译器"准备充分"------在编译时就知道该用哪条指令、数据布局如何,因此可以生成紧凑、无额外分支的机器码;循环里没有"这次是 int 还是 float"的判断,CPU 只是重复执行同一段指令。
  • Python:类型"随便"、多变,编译时准备不了唯一的一种机器码,只能每次运算时再查类型、再选实现;在密集循环里,这种"查表 + 间接调用"的开销会随着迭代次数线性放大,所以同样逻辑往往比 C++ 慢一个数量级以上。

这不是说"Python 不能快",而是说:在通用、动态语义下,标准实现选择的是"解释 + 运行时查类型",而不是"编译成一种固定的机器码";若要对某段 Python 做极致优化,要么用 C/C++/Cython 写扩展,要么依赖 JIT(如 PyPy)在运行时根据观测到的类型再生成机器码,本质上都是在"减少每次运算时的类型查找与间接"。


八、小结:一句话串起来

  • CPU 只认机器码;类型是语言和编译器/解释器之间的约定,用来决定"如何把人类写的运算变成 CPU 能做的操作"。
  • C++ 用静态类型在编译时就定死布局与指令,编译器一次性生成机器码,CPU 直接执行。
  • Python 用动态类型在运行时才确定类型,解释器每次运算都要查类型、选实现,再通过底层 C 等代码间接变成 CPU 指令。
  • 因此:类型何时、如何确定,决定了是谁(编译器 vs 解释器)、在何时(编译时 vs 运行时)把代码变成 CPU 指令,也决定了密集计算能多接近"裸机器码"的执行效率。
相关推荐
ysa051030几秒前
斐波那契上斐波那契【矩阵快速幂】
数据结构·c++·笔记·算法
咚为2 分钟前
Rust 经典面试题255道
开发语言·面试·rust
吃一根烤肠5 分钟前
NumPy 内置函数与数组运算完全指南
python·numpy
VBsemi-专注于MOSFET研发定制6 分钟前
AI训练服务器8GPU功率链路设计实战:效率、可靠性与功率密度的平衡之道
运维·服务器·人工智能
北京耐用通信8 分钟前
1个网关=100+设备兼容:耐达讯自动化CC-Link IE 转 EtherCAT重新定义工业协议转换价值
人工智能·科技·网络协议·自动化·信息与通信
十六年开源服务商9 分钟前
家庭装修公司网站方案策划2026
java·开发语言
想你依然心痛10 分钟前
HarmonyOS 5.0运动健康APP开发实战:基于多传感器融合与AI教练的智能运动训练系统
人工智能·华为·harmonyos
Mr_Xuhhh11 分钟前
深入理解Java高级特性:反射、枚举与Lambda表达式实战指南
开发语言·python
XiYang-DING14 分钟前
【Java】TOP-K问题
java·开发语言
CHANG_THE_WORLD15 分钟前
模拟解析:宽度数组 `[1,2,1]`,10个条目的 XRef 流
java·前端·算法