執行Python 解釋器相關說明
Python 解釋器是能夠執行用其他計算機語言編寫的程序的系統軟件,它是一種翻譯程序,相比之下,源代碼解釋器更易于創建,并且不需要一個獨立的編譯過程,這大大的增進了開發人員的興趣。
到了這一步,子線程將自己掛起,操作系統的線程調度機制再也不能靠自身的力量將其喚醒,只有等待Python的線程調度機制強迫主線程放棄GIL后。子線程才會被喚醒;而子線程被喚醒之后,主線程卻又陷入了苦苦地等待中,同樣苦苦地守望著Python強迫子線程放棄GIL的那一刻。
當子線程被Python的線程調度機制喚醒之后,它所作的第一件事就是通過PyThreadState_Swap將Python維護的當前線程狀態對象設置為其自身的狀態對象,一如操作系統的進程上下文環境恢復一樣。
現在我們的子線程開始等待GIL,但是注意,線程的初始化還沒有真正完成,因為子線程還沒有順利進入字節碼解釋器。當Python線程調度將子線程喚醒之后。子線程將回到t_bootstrap中,并進入PyEval_CallObjectWithKeywords,從這里一直往前,最終將調用PyEval_EvalFrameEx,進入Python 解釋器。到了那個時候,子線程和主線程一樣,就完全被Python線程調度機制所控制了。
需要注意的是,PyThread_start_new_thread是在主線程中執行的,而從bootstrap開始,則是在子線程中執行的。其中涉及線程銷毀的動作,如PyThreadState_ DeleteCurrent等,將在后續的部分剖析。
到了這里,讀者可能有些疑惑了,我們花費了大量篇幅剖析的線程狀態對象鏈表似乎沒有什么用啊。其實不然,試想一下。
當線程調度發生時,在Python一級,需要通過之前剖析過的PyTrheadState_Swap函數切換當前的線程狀態對象,這時候就需要根據線程id從線程狀態對象鏈表中獲取線程對象了。
事實上,在Python內部的許多API中,比如PyGILState_Ensure等等中,都會涉及這個鏈表,這些API在C與Python交互時可能被大量調用,有興趣的讀者可以自行深入探索一下。
Python 解釋器包括兩個主要的子系統:一個是表達式解析器,負責處理數字表達式;另一個是解釋器,負責程序的實際執行。對于前者,可采用本書第2章所介紹的表達式解析器。但是在這里做了某些改進,使得解析器能夠解析包含在程序語句中的數字表達式,而不是只能解析孤立的表達式。
解釋器子系統和解析器子系統包含在同一個解釋器類中,該類名為SBasic。盡管從理論上講可以使用兩個獨立的類:一個包含Python 解釋器,另一個包含表達式解析器;但是將兩者用同一個類來實現的代效率會更高。
因為表達式解析器和Python 解釋器的代碼是密不可分的。例如,兩個子系統都操作保存著程序代碼的同一個字符數組。如果將它們分別安排在兩個類中,將會增加可觀的額外開銷,并導致性能上的損失和功能上的重復。此外,由于程序解釋的任務繁重,而解析表達式只是其中的一部分,因此將整個解釋機制包含在單個類中是很有意義的。
Python 解釋器執行時,每次從程序的源代碼中讀入一個標識符。如果讀入的是關鍵字,解釋器就按照該關鍵字的要求執行規定的操作。舉例來說,當解釋器讀入一個PRINT后,它將打印PRINT之后的字符;當讀入一個GOSUB時,它就執行指定的子程序。在到達程序的結尾之前,這個過程將反復進行。可以看到,解釋器只是簡單地執行程序指定的動作。
【編輯推薦】