並行運行多個python虛擬機


之前遇到一個問題,需要將場景服務這個模塊拆分出來,用獨立的一個線程去執行。使用獨立的線程好處就是,邏輯寫的可以相對簡單粗暴點,不必考慮到大量的場景服務邏輯卡主線程的情況。

由於我們服務器之前是使用python作為腳本開發,而大家都知道的python有個gil,這意味着並發的線程里只有一個可以獲得解釋器的全局鎖,從而並執行python代碼。當然了python這樣子也是有原因的,由於其內部使用了大量的靜態變量,因此多線程環境下必須有一個線程同步的機制。結果最后選擇了在服務器又再嵌入了一個(多個)lua虛擬機,把場景服務用lua來寫。

 

但是,實際上我們是可以做到在一個進程內做到並行的運行多個python虛擬機的,只不過過程稍微曲折一點。基本的思想就是,重復導入多份python動態鏈接庫,每個線程上運行完全獨立的python代碼

在Linux下就可以通過dlopen運行時動態的導入一個so模塊,使用dlmopen則可以重復的導入多份相同的so。dlopen:https://docs.oracle.com/cd/E23824_01/html/821-1465/dlmopen-3c.html#scrolltoc

windows下則不得不在文件系統上保存多份python.dll的實例,並且在運行時通過LoadLibrary分別導入這些dll。LoadLibrary:https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms684175(v=vs.85).aspx

 

基於上述思路我大致簡單實現了一下:

https://github.com/adinosaur/python-vm

有幾點要說明的是:

調用Py_Initialize初始化python以及后續調用其它cpython的api必須在同一個線程內,否則在debug版的python中會報沒有獲得解釋器鎖而調用cpython api的錯誤,從而終止程序。

調用動態鏈接庫里的函數這部分代碼需要特別注意,雖然在熟知動態連接庫使用的調用約定后(比如gcc可能是cdecl,msvc可能是stdcall),是可以將這部分代碼寫的十分精簡通用的。但因為目前我還沒做到,因此選擇了保守的枚舉法:)

linux下使用dlmopen導入多份libpython.so,執行時會有段錯誤,具體原因尚未查明。因此我的實現中在linux下也是像windows那樣,在文件系統中存多份動態鏈接庫的實例。

 

參考連接:

https://stackoverflow.com/questions/1745975/load-multiple-copies-of-a-shared-library


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM