亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是否可以直接采用類hashtable的形式來做?

是否可以直接采用類hashtable的形式來做?

九州編程 2023-05-01 18:14:07
問題背景: Python在執行的時候會加載每一個模塊的PyCodeObject,其中這個對象就包含有opcode,也就是這個模塊所有的指令集合,具體定義在源碼目錄的 /include/opcode.h 中定義了所有的指令集合,在執行的時候通過加載opcode完成指令的流水線執行過程,opcode也就是所有指令集合生成的字符串。執行體位于源碼目錄的 /Python/ceavl.c 中PyEval_EvalFrameEx()函數就是虛擬機的執行體函數,它會加載指令集合并完成運算。問題描述: 在PyEval_EvalFrameEx()函數中,同樣是通過標準狀態機模型完成的指令解析,一個巨大無比的switch結構,類似這樣:在C中,switch語句的執行是逐條對比的,也就是說每一條指令在執行的時候都需要從頭對比,因為這里的指令集合是不平均分布的,但是我們可以假設每個指令平均需要匹配n次,n > 1,其實是遠遠大于1的。具體問題: 是否可以做優化,為什么作者沒有做優化? 如果不采用switch狀態機,因為指令碼也是有編號的,是否可以直接采用類hashtable的形式來做?
查看完整描述

1 回答

?
慕妹3146593

TA貢獻1820條經驗 獲得超9個贊

比較稀疏的switch(指case的值之間相差得比較大)確實是需要一次次地比較才能選定到底應該進入哪個分支。不過CPython的這個ceval.c里的switch是非常稠密的,case之間的值相差都是1,因此流行的編譯器(gcc/msvc/llvm-clang)都能夠將這個switch轉化為簡單的indirect branch,比如以x86-64,linux,gas syntax為例:

cmp $MAX_OP, %opcodeja .handle_max_op
jmp *.op_dispatch_table(,%opcode,8)

翻譯成C的話,大致意思是這樣:

static void *op_dispatch_table[] = {
    &&handle_NOP,
    &&handle_LOAD_FAST,    // etc etc...};if (opcode > MAX_OP) {    goto *handle_max_op;
}else {    goto *op_dispatch_table[opcode];
}

所以其實并不會像你所說的那樣逐條比較。

Interpreter的優化是很有意思的。switch看似高效,但是實際上由于生成的代碼會在同一個地方進行所有的indirect branch(分支目標可以是任何地方),處理器的分支預測就變得毫無用處了。

分支預測在CPython這種基于棧的解釋器里非常重要,這是因為大部分的OPCODE都較短,opcode dispatch(也就是分支預測)花的時間經常能占到大頭。在大家常用的Sandy Bridge處理器里,分支預測失敗相當于15個cycle,而IPC(每cycle能執行的CPU指令)在分支預測成功的情況下一般能達到3。相比之下,LOAD_FAST這種小型的OPCODE僅僅只用到了不到10個CPU指令.. 也就是說,分支預測所花的時間,甚至能占到整個code運行時間的80%。

因此,CPython使用了另外兩個優化技巧,一是對常用連續指令的預測,二是如果編譯器支持則使用indirect threading。

連續指令的預測,指的是由于Python中,有很多指令經常成對出現(比如在if x < y then xxx else xxx里會出現COMPARE_OP -> POP_JUMP_IF_FALSE)。這種情況下,前一個OPCODE并不需要依靠switch來執行后一個OPCODE,它可以自己跳到后一個OPCODE上去,需要做的只是檢查一下后一個OPCODE是不是自己所想要的而已。這里需要添加兩個分支,但是這兩個分支一個是條件判斷,一個是直接跳過去,所以處理器的分支預測可以在這里發揮作用。在ceval.c里,如果你看到了PREDICT(...)的字樣,那就說明這里有連續指令的預測了。

indirect threading,指的是將indirect branch放在每個OPCODE處理的結尾部分。這樣一來,每個OPCODE就會獲得處理器針對自己下一個指令的分支預測。雖然這依然是indirect branch,但是由于每個OPCODE分開預測,這大大提高了預測的準確度。CPython2.7并沒有用到這個優化。CPython3+會根據編譯器支持與否,來開關這個選項。

CPython的解釋器,經過多年的打磨,優化那是剛剛的。


查看完整回答
反對 回復 2023-05-03
  • 1 回答
  • 0 關注
  • 137 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號