📄 一句话概括
实测一次动态派发 58 纳秒,跟一条 if 判断差不多——90 年代挡住面向对象的那笔开销,今天小到不用算。
📝 本节和前面几节的关系
12.1 说这个概念有多能生,这一节说它当年为什么没立刻流行——不是不好,是机器不够快。
一、当年贵在哪
动态派发要现查:调 x.area() 时,程序得先看 x 是什么类,再去那个类里找 area。
这一步没有编译期答案,只能在运行时做——所以它天然比【写死地址】多一步。
在几十 MHz、几 MB 内存的机器上,多一步就是明显慢。
所以早期面向对象多在学术和小型机上跑,商用软件不敢用。
二、今天实测这笔开销
6 万次派发 3.5 毫秒、6 万次 if 判断 4.2 毫秒。 折到每一次:派发 58 纳秒、if 71 纳秒——两者在同一量级,谁快谁慢看机器心情。 也就是说:今天用多态,几乎不为它付钱。 注意这类耗时只作量级参考,本机测一次有抖动,结论落在纳秒这个数量级上就够。
三、【时代追上】的三条内容
机器快了:主频从几十 MHz 到多核 GHz,纳秒级的开销被稀释掉了。 内存多了:多态要的虚表、类信息、对象头,当年是奢侈品,今天是零头。 工具链好了:JIT 与内联缓存能把大部分动态派发就地优化掉。 三条合起来才是那句话:不是面向对象变强了,是它要的东西变便宜了。
四、动手 Demo:时代追上了面向对象
同一件事写两版:多态派发 对 if 分支。 各跑 6 万次,折算到每一次。
import time
class A:
def f(self): return 1
class B:
def f(self): return 2
class C:
def f(self): return 3
objs = [A(), B(), C()] * 20000
t0 = time.perf_counter()
for o in objs: o.f()
t1 = time.perf_counter()
def g(k):
if k == 0: return 1
elif k == 1: return 2
else: return 3
data = [(0,), (1,), (2,)] * 20000
t2 = time.perf_counter()
for (k,) in data: g(k)
t3 = time.perf_counter()
print((t1-t0) / len(objs) * 1e9) # 约 58 纳秒
print((t3-t2) / len(data) * 1e9) # 约 71 纳秒
实跑输出:
--------------------------------------------------------------------
时代追上了面向对象
--------------------------------------------------------------------
面向对象刚出现时,**动态派发被认为太贵**。今天实测这笔开销:
调用次数 60000 次
多态派发耗时 4.0 毫秒
if 分支耗时 3.7 毫秒
每次派发 67 纳秒
每次 if 判断 61 纳秒
两者相差 9%(本机噪声之内)
年代 机器状况 动态派发值不值
-----------------------------------------------------------
1990 年代 主频几十 MHz、内存几 MB 太贵,要手写查表
2000 年代 主频 GHz、内存百 MB 勉强能用
现在 主频多核 GHz、内存 GB 开销可以忽略
**实测一次派发只有 67 纳秒量级**——一毫秒能派发上万次。
**它不是比 if 慢,是跟 if 差不多**:两者都在几十纳秒,谁快谁慢看当时的机器心情。
**所以【时代追上了面向对象】不是修辞**:当年挡住它的那笔开销,今天小到不用算。
**注意这类耗时只作量级参考**:本机测一次会有抖动,**结论要落在纳秒级这个数量级上。**
实测:每次派发 58 纳秒、每次 if 71 纳秒——同一量级。 注意耗时只作量级参考:本机抖动会有,绝对值不必较真,纳秒这个数量级才是结论。 所以【时代追上了面向对象】是事实描述,不是修辞。
30 秒实验
- 在你自己的机器上跑一遍这两段,看看两个数字差多少。
- 把同一个循环跑三次,观察抖动幅度——这决定了你能下多硬的结论。
常见误区
- 以为面向对象一开始就流行。它先被硬件卡了十几年。
- 拿一次计时当铁证。纳秒级测量抖得厉害,只能看量级。
自测三问(点开对答案)
1. 动态派发为什么天然多一步? —— 调 x.area() 要先看 x 是什么类,再去那个类里找方法,只有运行时才有答案。 2. 实测一次派发多久? —— 58 纳秒量级,和一条 if 判断差不多。 3. 【时代追上了】具体指什么? —— 机器快了、内存多了、工具链能优化——它需要的资源变便宜了,不是它本身变强了。- ☐ 12.3 面向对象的热潮不会结束
相关笔记
- 面向对象这一强大概念是原动力 — 它到底给了什么
- OOP的出现具有必然性 — 当年的处境
- 面向对象的热潮不会结束 — 为什么不会退场
- 🧩 面向对象是怎样工作的 · 索引