mwo*_*mwo 8 python cpython multiplication
基本上,该表达式0.4 * a始终比a * 0.4. a是一个整数。我不知道为什么。
我推测这是LOAD_CONST LOAD_FAST字节码对比 更“专业”的情况LOAD_FAST LOAD_CONST,我对这个解释完全满意,除了这个怪癖似乎只适用于乘法变量类型不同的乘法。(顺便问一下,我曾经在github上找到的这个“字节码指令对流行度排名”的链接现在已经找不到了,有人有链接吗?)
无论如何,这是微观基准:
$ python3.10 -m pyperf timeit -s"a = 9" "a * 0.4"
Mean +- std dev: 34.2 ns +- 0.2 ns
Run Code Online (Sandbox Code Playgroud)
$ python3.10 -m pyperf timeit -s"a = 9" "0.4 * a"
Mean +- std dev: 30.8 ns +- 0.1 ns
Run Code Online (Sandbox Code Playgroud)
$ python3.10 -m pyperf timeit -s"a = 0.4" "a * 9"
Mean +- std dev: 30.3 ns +- 0.3 ns
Run Code Online (Sandbox Code Playgroud)
$ python3.10 -m pyperf timeit -s"a = 0.4" "9 * a"
Mean +- std dev: 33.6 ns +- 0.3 ns
Run Code Online (Sandbox Code Playgroud)
正如您所看到的 - 在浮动首先出现的运行中(第二次和第三次) - 它更快。
所以我的问题是这种行为从何而来?我 90% 确定它是 CPython 的实现细节,但我不太熟悉低级指令来确定这一点。
它是操作码的 CPython 实现BINARY_MULTIPLY。它在编译时不知道类型是什么,因此一切都必须在运行时弄清楚。不管是什么a并且b可能是什么,BINARY_MULTIPLY最终都会 inoking a.__mul__(b)。
当ais 是 int 类型时int.__mul__(a, b),不知道该怎么做,除非b也是 int 类型。它返回Py_RETURN_NOTIMPLEMENTED(一个内部 C 常量)。这是在longobject.c的CHECK_BINOP宏中。口译员明白了这一点,并有效地说“好吧,a.__mul__不知道该怎么做,所以让我们尝试一下b.__rmul__”。这些都不是免费的——这一切都需要时间。
float.__mul__(b, a)(与 相同float.__rmul__)确实知道如何处理 int (首先将其转换为 float),因此成功。
但是当a开始是float类型时,我们就先到这里float.__mul__,然后就结束了。无需花时间去弄清楚 int 类型不知道该怎么做。
实际的代码比上面假装的要复杂得多,但这就是要点。
| 归档时间: |
|
| 查看次数: |
188 次 |
| 最近记录: |