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