You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何小数值场景下乘法运算比位运算移位更快?

位运算移位为何在小数值下比乘法慢?

现象观察

先看两组性能测试的结果:

第一组测试取多次运行的最小值:

from timeit import repeat
for e in ['x*2 ', 'x<<1'] * 3:
    print(e, min(repeat(e, 'x=5')))

输出:

x*2  0.015567475988063961
x<<1 0.024531989998649806
x*2  0.01551242297864519
x<<1 0.024578287004260346
x*2  0.015560572996037081
x<<1 0.02448918900336139

可以看到小数值x=5时,x*2的耗时明显比x<<1低,且这个差异在x到10亿时都存在,仅随倍数增大而缩小。

第二组测试取多次运行的最大值:

for e in ['x*2 ', 'x<<1'] * 3:
     print(e, max(repeat(e, 'x=5')))

输出:

x*2  0.054458492988487706
x<<1 0.02453691599657759
x*2  0.015550968993920833
x<<1 0.0246038619952742
x*2  0.015542584005743265
x<<1 0.024583352991612628

这里x*2首次执行耗时远高于移位,后续则和移位耗时相近。

原因解析

1. 小整数场景下的解释器优化差异

Python对**-5到256之间的小整数**有全局缓存池,避免重复创建对象。而乘法和移位的字节码实现逻辑存在差异:

  • BINARY_MULTIPLY(乘法操作码)针对小整数有更直接的快速路径,计算结果直接命中缓存,几乎不需要额外操作;
  • BINARY_LSHIFT(移位操作码)虽然结果相同,但执行时会额外做一些检查(比如移位位数的合法性、整数内部存储格式的适配),这些额外步骤在小数值场景下的开销占比更高,导致整体耗时增加。

另外,现代CPU的乘法指令本身已经非常高效,对于2的幂次乘法,CPU会自动优化为移位操作,但Python解释器的层面开销(操作码处理、对象检查等)掩盖了硬件层面的优势,小数值下解释器的逻辑差异成为性能主导因素。

当x增大到10亿这类超出小整数缓存池的数值时,乘法和移位都需要创建新的大整数对象,此时对象创建的开销占比更大,两者的操作逻辑差异被稀释,耗时差也就缩小了。

2. 首次执行的字节码编译开销

timeit.repeat执行表达式时,首次需要将字符串形式的代码编译为字节码(生成PyCodeObject),这个编译过程存在固定开销:

  • x*2的表达式编译逻辑相对复杂,首次编译耗时更高;
  • x*2后续执行时复用了已经编译好的字节码,耗时直接降到和移位相近的水平;
  • 移位表达式的编译开销本身较小,所以首次和后续执行的耗时差异不明显。

验证:查看字节码

可以用dis模块对比两个表达式的字节码:

import dis
dis.dis("x*2")
dis.dis("x<<1")

输出:

# x*2的字节码
  1           0 LOAD_NAME                0 (x)
              2 LOAD_CONST               0 (2)
              4 BINARY_MULTIPLY
              6 RETURN_VALUE

# x<<1的字节码
  1           0 LOAD_NAME                0 (x)
              2 LOAD_CONST               0 (1)
              4 BINARY_LSHIFT
              6 RETURN_VALUE

字节码结构几乎一致,但底层C实现的逻辑差异才是性能差的核心。

内容的提问来源于stack exchange,提问作者Woody1193

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:10:35