Python虛擬機框架知識點有哪些-創(chuàng)新互聯(lián)

成都創(chuàng)新互聯(lián)公司專注于企業(yè)網(wǎng)絡(luò)營銷推廣、網(wǎng)站重做改版、寧陜網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、html5商城網(wǎng)站制作、集團公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為寧陜等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

這篇文章主要介紹Python虛擬機框架知識點有哪些,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

  Python虛擬機框架知識點講解:


  一、Python字節(jié)碼


  我們知道,Python源代碼在執(zhí)行前,會先將源代碼編譯為字節(jié)碼序列,Python虛擬機就根據(jù)這些字節(jié)碼進行一系列的操作,從而完成對Python程序的執(zhí)行。在Python2.5中,一共定義了104條字節(jié)碼指令:


  opcode.h

Python虛擬機框架知識點有哪些
  如果我們仔細看上面的字節(jié)碼指令,會發(fā)現(xiàn)雖然字節(jié)碼是從0定義到143,但中間有發(fā)生跳躍,比方5直接跳躍到9,13直接跳躍到15,15直接跳躍到18。所以,Python2.5實際上只定義了104條字節(jié)碼指令


  在Python2.5的104條指令中,有一部分需要參數(shù),另一部分是沒有參數(shù)的。所有需要參數(shù)的字節(jié)碼指令的編碼都是大于90。Python中提供了專門的宏來判斷一條字節(jié)碼指令是否需要參數(shù):


  opcode.h

Python虛擬機框架知識點有哪些
  我們在Python之code對象與pyc文件(一)、Python之code對象與pyc文件(二)和Python之code對象與pyc文件(三)介紹了PyCodeObject對象,這個對象是Python對源代碼進行編譯后在內(nèi)存中產(chǎn)生的靜態(tài)對象,這個對象當然也包含了源代碼編譯后的字節(jié)碼,我們可以用Python提供的code對象解析工具dis對其進行解析

Python虛擬機框架知識點有哪些
  最左邊的一列是字節(jié)碼指令在源代碼中所對應(yīng)的行數(shù),左起第二列是當前字節(jié)碼在co_code中的偏移位置,第三列顯示了當前字節(jié)碼的指令,第四列是指令的參數(shù),最后一列是計算后的實際參數(shù)


  二、Python虛擬機的運行框架


  當Python啟動后,首先會進行Python運行時環(huán)境的初始化。注意,這里的運行時環(huán)境與之前的章節(jié)《Python之code對象與pyc文件》中的執(zhí)行環(huán)境是不同的。運行時環(huán)境是一個全局的概念,而執(zhí)行環(huán)境實際就是一個棧幀。是一個與某個Code Block對應(yīng)的概念。而Python虛擬機的實現(xiàn),是在一個函數(shù)中,這里我們列一下源碼,與實際的源代碼會做一些刪改:


  ceval.c

Python虛擬機框架知識點有哪些
  PyEval_EvalFrameEx首先會初始化一些變量,其中PyFrameObject對象中的PyCodeObject對象包含的重要信息都被照顧到了。當然,另一個重要的動作就是初始化了堆棧的棧頂指針stack_pointer,使其指向f->f_stacktop。PyCodeObject對象中的co_code域中保存著字節(jié)碼指令和字節(jié)碼指令的參數(shù),Python虛擬機執(zhí)行字節(jié)碼指令序列的過程就是從頭到尾遍歷整個co_code、依次執(zhí)行字節(jié)碼指令的過程。


  在Python虛擬機中,利用3個變量來完成整個遍歷過程。co_code實際上是一個PyStringObject對象,而其中的字符數(shù)組才是真正有意義的東西,整個字節(jié)碼指令序列實際上在C中就是一個字符數(shù)組。因此,遍歷過程中所使用的3個變量都是char *類型的變量,first_instr永遠指向字節(jié)碼指令序列的開始位置,next_instr永遠指向下一條待執(zhí)行的字節(jié)碼指令的位置,f_lasti指向上一條已經(jīng)執(zhí)行過的字節(jié)碼指令的位置。

Python虛擬機框架知識點有哪些

       圖1-1展示了3個變量在遍歷中某時刻的情景
  
  Python虛擬機執(zhí)行字節(jié)碼指令的架構(gòu),其實就是一個for循環(huán)加上一個巨大的switch/case結(jié)構(gòu):


  ceval.c

Python虛擬機框架知識點有哪些
  上面的代碼只是一個極度簡化之后的Python虛擬機的樣子,完整的代碼實現(xiàn)在ceval.c文件的PyEval_EvalFrameEx方法中。


  在這個執(zhí)行架構(gòu)中,對字節(jié)碼的一步一步地遍歷是通過幾個宏來實現(xiàn)的:

  ceval.c

Python虛擬機框架知識點有哪些
  在對PyCodeObject對象分析中我們說過,Python字節(jié)碼有的是帶參數(shù)的,有的是沒帶參數(shù)的,判斷字節(jié)碼是否帶參數(shù)具體參考HAS_ARG這個宏的實現(xiàn),對于不同字節(jié)碼指令,由于存在是否需要指令參數(shù)的區(qū)別,所以next_instr的位移可能是不同的,但無論如何,next_instr總是指向Python下一條要執(zhí)行的字節(jié)碼。


  Python在獲得了一條字節(jié)碼和其需要的指令參數(shù)后,會對字節(jié)碼指令利用switch進行判斷,根據(jù)判斷的結(jié)果選擇不同的case語句,每一條字節(jié)碼指令都會對應(yīng)一個case語句。在case語句中,就是Python對字節(jié)碼指令的實現(xiàn)。


  在成功執(zhí)行完一條字節(jié)碼指令后,Python的執(zhí)行流程會跳轉(zhuǎn)到fast_next_opcode處,或者是for循環(huán)處,不管如何,Python接下來的動作都是獲得下一條字節(jié)碼指令和指令參數(shù),完成對下一條指令的執(zhí)行。如此一條一條地遍歷co_code中包含的所有字節(jié)碼指令,最終完成了對Python程序的執(zhí)行。


  這里還需要提到一個變量"why",它指示了退出這個巨大的for循環(huán)時Python執(zhí)行引擎的狀態(tài),因為Python執(zhí)行引擎不一定每次執(zhí)行都會正確無誤,很有可能在執(zhí)行某條字節(jié)碼時產(chǎn)生了錯誤,這就是我們熟悉的異常——exception。所以在Python退出執(zhí)行引擎的時候,就需要知道執(zhí)行引擎是因為什么而結(jié)束的,是正常結(jié)束呢?還是因為錯誤的發(fā)生,無法執(zhí)行下去了?why就承擔起這一重則變量why的取值范圍在ceval.c中被定義,其實也是Python結(jié)束字節(jié)碼執(zhí)行時的狀態(tài):
  ceval.c

Python虛擬機框架知識點有哪些
  三、Python運行時環(huán)境初探


  前面我們說過,PyFrameObject對應(yīng)于可執(zhí)行文件在執(zhí)行時的棧幀,但一個可執(zhí)行文件要在操作系統(tǒng)中運行只有棧幀是不夠的,我們還忽略了兩個對于可執(zhí)行文件至關(guān)重要的概念:進程和線程。Python在初始化時會創(chuàng)建一個主線程,所以其運行環(huán)境中存在一個主線程。因為在后面剖析Python異常機制會利用到Python內(nèi)部的線程模型,因此,我們需要對Python線程模型有一個整體概念上的了解。


  以Win32平臺為例,我們知道,對于原生Win32可執(zhí)行文件,都會在一個進程內(nèi)執(zhí)行。進程并非是與機器指令序列相對應(yīng)的活動對象,這個可執(zhí)行文件中機器指令序列對應(yīng)的活動對象是由線程這個概念來進行抽象的,而進程則是線程的活動環(huán)境。


  對于通常的單線程可執(zhí)行文件,在執(zhí)行時操作系統(tǒng)會創(chuàng)建一個進程,在進程中,又會有一個主線程,而對于多線程的可執(zhí)行文件,在執(zhí)行時操作系統(tǒng)會創(chuàng)建出一個進程和多個線程,該多個線程能共享進程地址空間中的全局變量,這就自然而然地引出線程同步的問題。CPU對任務(wù)的切換實際上是在線程間切換,在切換任務(wù)時,CPU需要執(zhí)行線程環(huán)境的保存工作,而在切換至新線程后,需要恢復(fù)該線程的線程環(huán)境。


  前面我們所看到的Python虛擬機的運行框架,實際上就是對CPU的抽象,可以看做一個軟CPU,Python中所有線程都使用這個軟CPU來完成計算工作。真實機器的任務(wù)切換機制對應(yīng)到Python中,就是使不同的線程輪流使用虛擬機的機制。


  CPU切換任務(wù)時需要保存線程運行環(huán)境。對于Python來說,在切換線程之前,同樣需要保存關(guān)于當前線程的信息。在Python中,這個關(guān)于線程狀態(tài)信息的抽象是通過PyThreadState對象來實現(xiàn)的,一個線程將擁有一個PyThreadState對象。所以從另一種意義來說,這個PyThreadState對象也可以看成是線程本身的抽象。但實際上,這兩者是有很大的區(qū)別的,PyThreadState并非是對線程本身的模擬,因為Python中的線程仍然使用操作系統(tǒng)的原生線程,PyThreadState僅僅是對線程狀態(tài)的抽象。


  在Win32下,線程是不能獨立存活的,它需要存活在進程的環(huán)境中,而多個線程可以共享進程的一些資源。在Python中也是一樣,如果Python程序中有兩個線程,都會進行同樣一個動作——import sys,那么這個sys module應(yīng)該存多少份?是全局共享還是每個線程但單獨一個sys module?如果每個線程單獨一份sys module,那么對Python內(nèi)存的消耗會非常的驚人,所以在Python中,module都是全局共享的,仿佛這些module都是進程中的共享資源一樣,對于進程這個概念,Python以PyInterpreterState對象來實現(xiàn)。


  在Win32下,通常都會有多個進程,而Python實際上也可以由多個邏輯上的interpreter存在。在通常情況下,Python只有一個interpreter,這個interpreter中維護了一個或多個的PyThreadState對象,與這些PyThreadState對象對應(yīng)的線程輪流使用一個字節(jié)碼執(zhí)行引擎。


  現(xiàn)在,展示一下剛提到的表示進程概念的PyInterpreterState對象和表示線程概念的PyThreadState對象:


  pystate.h

Python虛擬機框架知識點有哪些Python虛擬機框架知識點有哪些
  在PyThreadState對象中,我們看到熟悉的PyFrameObject(_frame)對象。也就是說,在每個PyThreadState對象中,會維護一個棧幀列表,以與PyThreadState對象的線程中的函數(shù)調(diào)用機制對應(yīng)。在Win32上,情形也是一樣,每個線程都會有一個函數(shù)調(diào)用棧


  當Python虛擬機開始執(zhí)行時,會將當前線程狀態(tài)對象中的frame設(shè)置為當前的執(zhí)行環(huán)境(frame):

Python虛擬機框架知識點有哪些
  而在建立新的PyFrameObject對象時,則從當前線程的狀態(tài)對象中取出舊的frame,建立PyFrameObject鏈表:

Python虛擬機框架知識點有哪些

以上是“Python虛擬機框架知識點有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!

本文題目:Python虛擬機框架知識點有哪些-創(chuàng)新互聯(lián)
網(wǎng)頁鏈接:http://www.muchs.cn/article46/dodeeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、網(wǎng)站內(nèi)鏈、云服務(wù)器、品牌網(wǎng)站設(shè)計品牌網(wǎng)站建設(shè)、品牌網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)