創(chuàng)新互聯(lián)www.cdcxhl.cn八線動態(tài)BGP香港云服務(wù)器提供商,新人活動買多久送多久,劃算不套路!
創(chuàng)新互聯(lián)致力于做網(wǎng)站、網(wǎng)站設(shè)計,成都網(wǎng)站設(shè)計,集團網(wǎng)站建設(shè)等服務(wù)標(biāo)準(zhǔn)化,推過標(biāo)準(zhǔn)化降低中小企業(yè)的建站的成本,并持續(xù)提升建站的定制化服務(wù)水平進行質(zhì)量交付,讓企業(yè)網(wǎng)站從市場競爭中脫穎而出。 選擇創(chuàng)新互聯(lián),就選擇了安全、穩(wěn)定、美觀的網(wǎng)站建設(shè)服務(wù)!小編給大家分享一下Python編寫EVE的具體思路,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討方法吧!
大多數(shù)熟悉EVE的人都知道,它是用Python語言編寫的,如果要說得更具體點,那就是Stackless Python。Stackless是在Python基礎(chǔ)上編寫的一套微線程框架,它能在不產(chǎn)生大量Python自身額外開銷的情況下同時容納數(shù)百萬條的線程。
但話還是要說回來,它畢竟還是Python,因此擺脫不了“解釋器全局鎖”(Global Interpreter Lock,下文將其簡稱為GIL)。
GIL是一個序列鎖,用來保證在任何時候都只能有一個線程利用Python解釋器(包括其所有數(shù)據(jù))來運行自己。因此,盡管Stackless Python感覺上好像具備多線程處理能力,但實際上它還是單線程的,只不過運用了任務(wù)分離、頻道、定時器及共享內(nèi)存等一系列招數(shù)而已。
其實過去有些協(xié)作式的多任務(wù)操作系統(tǒng)也是這樣干的,其好處是保證了所有線程都能被執(zhí)行,不會出現(xiàn)被操作系統(tǒng)提前結(jié)束這一情況(除非被操作系統(tǒng)懷疑非法宕機)。GIL的存在使得程序員在編寫游戲邏輯時能自信推斷出程序的全局狀態(tài),省去了一大堆采用異步回調(diào)函數(shù)的麻煩。
但這樣有一大缺點:由于EVE中有部分框架的代碼是用Python編寫的,因此它們都免不了GIL造成的負(fù)面影響。比如,一段用來讀取Python數(shù)據(jù)的C++語言代碼必須在獲得GIL后才能讀取一個字符串。
使用Python的任務(wù)都要獲得GIL才能合法地被處理,這樣等同于Python任務(wù)都是單線程執(zhí)行。
(這圖畫得不太好看,人家只是個程序員,不是美術(shù)師哦)
一言以蔽之,Stackless Python 代碼的運行速度不會高于你最快的那個CPU核心的速度。在一臺4核或8核CPU的服務(wù)器上,其中只有一核在超負(fù)荷運作,其他都沒派上用場。當(dāng)然,為了讓這些CPU核心物盡其用,我們可以在它們身上加載更多的節(jié)點。
對于EVE中許多無狀態(tài)或?qū)蚕頎顟B(tài)依賴度極低的代碼而言,這沒什么問題。但對于像太空模擬或空間站行走這樣高度依賴共享狀態(tài)的代碼而言,就成了一個大問題。
假設(shè)一個CPU核心就能處理所有的邏輯并且寫出來的Python代碼較為清晰,那我之前說的都不是什么問題。不過,想必我不用說大家也知道,盡管Gridlock等小組已經(jīng)在優(yōu)化工作方面做到了其極致,但我們現(xiàn)在面臨的情況依舊是單個CPU已經(jīng)無法處理一場大型會戰(zhàn)了。
最近上市的CPU速度是更快、緩存容量也更大、總線也更寬裕并且具備更好的執(zhí)行流水線,但在EVE需要其給力的地方,卻沒有任何進步。近期(也可能包括中長期)的趨勢是“橫向增長”,即同時運行多個CPU核心。
總體而言,多核CPU的流行對EVE的長遠(yuǎn)發(fā)展是一大利好。未來那些30乃至60核CPU的機器能夠很好地體現(xiàn)EVE集群部署方式的優(yōu)勢,這是因為CPU核心之間切換的效率將遠(yuǎn)遠(yuǎn)大于線程之間切換的效率。
但就目前而言,為了提升游戲運行速度,我們需要把網(wǎng)絡(luò)及通用讀寫這樣的EVE模塊從GIL中解放出來。
多核心、超標(biāo)量的硬件對當(dāng)今的網(wǎng)絡(luò)游戲來說,都是個好消息。這些游戲很適合這種架構(gòu),并且能很容易地進行并行處理??上τ谝蕾嘝ython的EVE來說,這就算不得好消息了。
那些對運行速度要求極高、不需要Python便利開發(fā)優(yōu)勢的EVE系統(tǒng)需要盡早擺脫GIL的束縛。CarbonIO在這個方向上可以說是向前邁進了一大步。
CarbonIO 是在StacklessIO 基礎(chǔ)上的一個自然提升。它實際上是個從頭寫起的全新引擎,目標(biāo)非常明確:讓網(wǎng)絡(luò)流量擺脫GIL的束縛,并且讓任何C++代碼也能這樣做。后半個目的是重頭戲,我們花了大半年才把它完成。
這里不得不先稍微提一下StacklessIO。對Stackless Python的網(wǎng)絡(luò)通信而言,它可以說是個質(zhì)的飛躍。通過讓網(wǎng)絡(luò)操作變得具有“無堆棧的意識”,StacklessIO可以將一個被鎖住的操作轉(zhuǎn)移到一個未被GIL鎖住的線程上,這樣該操作就可以繼續(xù)等候,而Stackless則繼續(xù)處理其他事務(wù)。
然后,該操作重新獲得GIL,告訴Stackless其操作已完成。這樣,接收端就可以同步進行,使得通訊速度可以達(dá)到操作系統(tǒng)級別,并且能基本上在第一時間內(nèi)回報給Python。
StacklessIO在沒有GIL的情況下完成Python請求
CarbonIO在此基礎(chǔ)上更上一層樓。由于它是在完全脫離于GIL的情況下運行多線程通信引擎,因此Python與該系統(tǒng)之間的交互便是完全獨立了。沒有Python的要求,它也能收發(fā)數(shù)據(jù)。
請允許我再強調(diào)一下:CarbonIO能在Python不作任何要求的情況下收發(fā)數(shù)據(jù)。這是并發(fā)性的,不需要GIL。
當(dāng)一個連接通過CarbonIO被建立后,系統(tǒng)會調(diào)用WSARecv()開始接收數(shù)據(jù)。與Python進程并行的線程池將這些數(shù)據(jù)解密、解壓縮然后轉(zhuǎn)義到數(shù)據(jù)包里。這些數(shù)據(jù)包會排隊,等著Python來處理。
當(dāng)Python覺得它需要一個數(shù)據(jù)包時,它會往下調(diào)用“可能已將此包準(zhǔn)備就緒”的CarbonIO。這意味著數(shù)據(jù)在離開隊列被返回整個過程中根本沒有用到GIL。這是一個瞬時過程,至少也有納秒那么快。這個并行讀取能力是CarbonIO的第一大好處。
第二大好處便是發(fā)送了。數(shù)據(jù)以其原始形式排在工作線程隊列里,然后便等著Python來調(diào)用了。
其間的壓縮、加密、打包及WSASend()調(diào)用都沒有觸及GIL而發(fā)生在另一個線程里,這樣操作系統(tǒng)便可以安排它運行在另一顆CPU上了。C++代碼也可以調(diào)用一個方法來這樣做,并不需要特別的架構(gòu)變更。StacklessIO也可以那樣做,但在脫離上述背景的情況下,這會變得很沒意義。
讓我們再來回顧一下之前提到的“已將此包準(zhǔn)備就緒”。但如果我們要安置一個C++回調(diào)鉤子函數(shù),使得非Python模塊能在不觸及Machonet的情況下獲得那個數(shù)據(jù),這可行嗎?行啊,這時我們要用的就是BlueNet了。
CarbonIO不停地進行數(shù)據(jù)接收,并且能在無Python介入的情況下告訴C++模塊數(shù)據(jù)已收到。
Machonet是一個大型功能集合,它負(fù)責(zé)對會話進行分流、導(dǎo)向及管理,負(fù)責(zé)對數(shù)據(jù)包的時間計劃/發(fā)送以及其他一系列將EVE撮合成一個有機整體的功能。
由于它是個Python模塊,因此所有的數(shù)據(jù)遲早都必須觸及那倒霉的GIL,無論數(shù)據(jù)在哪個節(jié)點。無論一個C++模塊的速度有多快,GIL仍然是個繞不過的瓶頸。這使得我們曾經(jīng)都不太愿意做大量的C++優(yōu)化,因為任何優(yōu)化后取得的優(yōu)勢都會被Machonet 中的GIL吞噬。
但現(xiàn)在情況不一樣了。
現(xiàn)在C++的系統(tǒng)能通過BlueNet收發(fā)數(shù)據(jù)包,無需再理會GIL。這原來是專門為了空間站行走設(shè)計的。空間站行走功能需要發(fā)送大量的表示移動的數(shù)據(jù)。
EVE中太空飛行的那部分功能所需要收發(fā)的數(shù)據(jù),我們以前可以用旁門左道的方法來解決,但對于如此近距離的人物動作,就不行了。之前我們做的預(yù)測顯示,即使把空間站行走發(fā)送數(shù)據(jù)的頻率控制在一般程度,該功能也會把整個服務(wù)器集群拖垮。
通過在沒有GIL干擾的情況下對流入/流出C++原生系統(tǒng)(比如物理系統(tǒng))的數(shù)據(jù)進行分流,BlueNet成功地解決了該問題。由于在這種情況下,數(shù)據(jù)還是保持著其原生態(tài),因此整個系統(tǒng)運行的速度就比之前提高了。
這個具體是怎么運作的呢?BlueNet保存著一份所有必要Machonet結(jié)構(gòu)的只讀拷貝,另外,所有的數(shù)據(jù)包前都會附上很小的一段(8到10個字節(jié)的)數(shù)據(jù)頭。這個數(shù)據(jù)頭里含有路徑信息。
當(dāng)BlueNet接到一個數(shù)據(jù)包時,它會對其進行檢測,然后合理地再分發(fā):要么轉(zhuǎn)發(fā)到另一個節(jié)點上,要么交給被本地的已注冊的C++應(yīng)用程序。如果它轉(zhuǎn)發(fā),那這個過程中將用不到GIL,根本不會調(diào)用Machonet/Python。
這意味著我們的代理服務(wù)器完全能以并行方式對BlueNet的數(shù)據(jù)包進行分流,而不必去經(jīng)過Python導(dǎo)致額外開銷的產(chǎn)生。那這效率究竟提高了多少呢?我們還無法確定,但在降低機器負(fù)載及延遲方面,它還是非常非常明顯的。實際上我們還不能將數(shù)據(jù)公開,因為它們好得難以置信。
除此之外,CarbonIO也包含了大量底層優(yōu)化,絕大多數(shù)都是小規(guī)模的速度提升,但把這些統(tǒng)統(tǒng)疊加起來,整個系統(tǒng)的運行速度也就有了顯著提高。以下幾點值得一提:
工作分組
雖然我很難在本文中把這事兒說得太細(xì),但CarbonIO非常出色地將工作分組來處理。
簡而言之,就是某些操作有了一個固定的開銷。網(wǎng)絡(luò)引擎有許多這樣的開銷,但其他所有具有重要意義的代碼也有大量開銷。通過一些別出心裁的技巧,我們是可以將許多這樣的工作合并在一起,這樣就只產(chǎn)生一次開銷。
就像把邏輯數(shù)據(jù)包都組合在一起發(fā)送在一個TCP/IP MTU里一樣(EVE一直就是這樣干的),CarbonIO將這一做法進一步深化。一個比較簡單的例子就是GIL獲取集合。
第一個要嘗試取得GIL的線程會先建立起一個隊列,這樣其他要獲取GIL的線程只需將自己的喚醒調(diào)用排在隊列末尾然后返回線程池就行。那GIL最后被取得時,第一個線程會吸干整個隊列,不必在每次IO喚醒時釋放/重拾GIL。
在一個繁忙的服務(wù)器上這種情況很多,因此這種改進對我們來說是一大利好。
openSSL 整合
CarbonIO用openSSL來實現(xiàn)SSL,并且能在不鎖定GIL的情況下與該協(xié)議數(shù)據(jù)通信。該庫只是用作一個BIO對而已,所有的數(shù)據(jù)導(dǎo)航還是由CarbonIO通過完成端口進行的。
這有助于我們循序漸進地讓EVE變得更安全,甚至將來可以把官方網(wǎng)站上的某些帳號管理功能挪到EVE客戶端上去,這樣可以更方便大家。
壓縮整合
CarbonIO能利用zlib或snappy對每一個數(shù)據(jù)包都進行壓縮/解壓縮,這一過程同樣是無需GIL的。
實戰(zhàn)檢驗
通過對一個繁忙的代理服務(wù)器(人數(shù)峰值大約1600人,一個平常工作日)的24小時數(shù)據(jù)的收集,我們發(fā)現(xiàn)CPU的總體使用率與單個用戶的CPU使用率都出現(xiàn)了大幅下降。
這都?xì)w功于CarbonIO的總體架構(gòu),其作用就是降低事務(wù)的開銷。當(dāng)服務(wù)器變得繁忙之后,這些優(yōu)化的效果會被逐漸增多且必須處理的事務(wù)所抵消,但在最高負(fù)載時,CarbonIO還是讓我們的游戲增速了不少。
以上為24小時內(nèi)單個用戶的CPU使用率
以上為同樣的24小時內(nèi)總體CPU使用率
至于SOL(星系)節(jié)點,由于它們的主要職責(zé)是游戲機制而非網(wǎng)絡(luò)管理,因此它們從該優(yōu)化中獲得的優(yōu)勢并不那么明顯,但我們還是看到它們的CPU使用率下降了8%-10%。
需要指出的是,在上述的檢驗中我們沒有運用BlueNet,沒有用CarbonIO的數(shù)據(jù)導(dǎo)航,也沒有用脫離GIL的數(shù)據(jù)壓縮/解壓縮。
總的來說,比起以前,EVE能更好地利用現(xiàn)代服務(wù)器硬件帶來的優(yōu)勢,能讓它在同樣的時間內(nèi)完成更多的工作,這樣就間接提升了一個系統(tǒng)所能進行的操作上限。
通過將我們的代碼盡量與GIL脫離,我們反而為那些真正需要用它的代碼騰出了空間。另外,由于不再有那么多代碼需要競相獲取GIL,系統(tǒng)的總體運行效率也會提升。有了BlueNet再加上很好的代碼優(yōu)化,提速空間已被打開。雖然最后的結(jié)果仍有待實踐檢驗,但至少,我們已經(jīng)消除了一大瓶頸。
看完了這篇文章,相信你對Python編寫EVE的具體思路有了一定的了解,想了解更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道,感謝各位的閱讀!