簡體   English   中英

為什么在 CPython 中 float * int 乘法比 int * float 快?

[英]Why is the float * int multiplication faster than int * float in CPython?

基本上,表達式0.4 * a始終且令人驚訝地明顯快於a * 0.4 a是 integer。 我不知道為什么。

我推測這是一個LOAD_CONST LOAD_FAST字節碼對比 LOAD_FAST LOAD_CONST “更專業”的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
$ python3.10 -m pyperf timeit -s"a = 9" "0.4 * a"
Mean +- std dev: 30.8 ns +- 0.1 ns
$ python3.10 -m pyperf timeit -s"a = 0.4" "a * 9"
Mean +- std dev: 30.3 ns +- 0.3 ns
$ python3.10 -m pyperf timeit -s"a = 0.4" "9 * a"
Mean +- std dev: 33.6 ns +- 0.3 ns

正如您所看到的 - 在浮動首先出現的運行(第 2 次和第 3 次)中 - 它更快。
所以我的問題是這種行為從何而來? 我 90% 確定它是 CPython 的實現細節,但我對 state 的低級指令不太熟悉。

這是 CPython 對BINARY_MULTIPLY操作碼的實現。 它不知道編譯時的類型是什么,所以一切都必須在運行時計算出來。 不管ab是什么, BINARY_MULTIPLY最終都會調用a.__mul__(b)

a是 int 類型時, int.__mul__(a, b)不知道該怎么做,除非b也是 int 類型。 它返回Py_RETURN_NOTIMPLEMENTED (一個內部 C 常量)。 這是在longobject.cCHECK_BINOP宏中。 解釋器對此進行了分析,並有效地說“好的, a.__mul__不知道該做什么,所以讓我們b.__rmul__ ”。 這些都不是免費的——這一切都需要時間。

float.__mul__(b, a) (與float.__rmul__相同)確實知道如何處理 int (首先將其轉換為 float),因此成功。

但是當a開始是 float 類型時,我們 go 先到float.__mul__ ,到此結束。 沒有時間花時間弄清楚 int 類型不知道該做什么。

實際的代碼比上面假裝的要復雜得多,但這就是它的要點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM