「动态分发更慢」这句话对不对?这篇用同一个遍历循环做四种对照:全是同一种类型、规律交替、随机排列、改用 enum。结论是:动态分发的代价不在「查 vtable」本身,而在分支预测与无法内联 —— 目标可预测时几乎免费,不可预测时慢好几倍。
编译:成功
运行(退出码 0):
泛型/静态分发 Vec<Circle>(可内联、可向量化) 每个对象 0.90 ns
动态分发 Vec<Box<dyn Shape>>,全是 Circle 每个对象 0.93 ns
动态分发,三种类型按 0,1,2,0,1,2 规律交替 每个对象 2.30 ns
动态分发,三种类型随机排列(分支预测失败) 每个对象 5.06 ns
enum 分发 Vec<AnyShape>(match,可内联) 每个对象 0.86 ns基准用 Instant 计时、release 构建,每种配置取 20 次中位数;这个循环本身受内存访问影响很大,所以静态分发没有显著领先于全是同一类型的 dyn。数字只对这台机器与这个负载有意义。
static_call(&Circle) 的汇编: ldr d0, [x0] ; mov x8, #34414 ; movk x8, #61467, lsl #16 ; movk x8, #8697, lsl #32 ; movk x8, #16393, lsl #48 ; fmov d1, x8 ; fmul d1, d0, d1 ; fmul d0, d0, d1 ; ret dyn_call(&dyn Shape) 的汇编: ldr x1, [x1, #24] ; br x1
对象怎么布局、胖指针里有什么,见Trait Object 与动态分发;单态化的代码体积代价见泛型单态化。