Python 於 webgame 的應用(下)

來源:互聯網
上載者:User

賴勇浩(http://laiyonghao.com)

(續上)

遊戲(伺服器)是一種 CPU 密集、I/O 密集的應用,但是因為 GIL 的原因,Python 不能充分利用多核,所以一般都採用分布式的方案,那麼 CPU 方面就沒有太多好講的了,不過 I/O 方面蠻有意思,可以講一下。這裡有沒有 node.js 社區的朋友?(有人舉手)。這句話你熟悉嗎?(投影片上是一句話:I/O needs to be done differently.)這句話是 node.js 的作者說的,他說 I/O 該用不同的方法來實現啦。我覺得他說得很對,……後來他也做了 node.js。這裡有一個 node.js 操作 DB 的例子,DB 操作必須是有 I/O,有 I/O 就有阻塞,有阻塞就並發性較差。node.js 是這樣解決的:


在操作資料庫的時候,指定一個回呼函數,在操作結束的時候,再由 node.js 把結果推送給你。藉助 javascript 強大的閉包文法,可以寫出“很漂亮”的帶有回調的程式,而且看起來好像阻塞程式一樣簡單,又帶有很高的並發效能。這就是 node.js 認為的 I/O 該有的樣子。但是我不認同這句話。我認為 I/O 應該這樣做,以下舉個頁遊編程中常見的例子:


上面是玩家輸入使用者名稱、密碼後按下登陸鍵,從帳號驗證到進入遊戲的流程。當使用者名稱、密碼發送到專門用以登陸的 signin 伺服器,signin 需要先查詢資料庫驗證使用者名稱、密碼。在此我們只考慮使用者名稱、密碼無誤的情況,signin 知道使用者名稱、密碼無誤之後,就得先告知 game 伺服器,game 伺服器會返回一個令牌給 signin,後面用戶端可以憑此令牌登陸 game 伺服器開始遊戲之旅。這麼複雜的流程,涉及到多條進程之間的通訊,也就是有許多的 I/O。這種應用使用 node.js 來寫的話,可能需要寫上兩三個回調,個人覺得是比較麻煩的。那麼我覺得 I/O 最好能夠像的代碼中那樣,……但這不就是傳統的阻塞式的 I/O 嗎?對的!我覺得 I/O 的介面應該跟之前無二,但是底層的實現需要改變;而不是像 node.js 一樣,都帶一毛 callback 的尾巴。那麼怎麼做到這一點呢?

解決方案就是協程,協程才是未來。接下來介紹一下 gevent,gevent 能夠讓的代碼運行起來。gevent 就是 libevent 加上 greenlet,簡單介紹一下這兩個庫。libevent 提供指定的檔案描述符事件發生時調用回呼函數的機制,當然 timeout、signals 等也會調用回調。所以底層其實跟 node.js 是一樣的,是有一個回呼函數的,但是可以通過 greenlet 來封裝出同步的 API,將醜陋的回調隱藏起來。greenlet 是一種 green thread……即一種使用者空間線程,提供偽並發機制,所謂偽並發就是它並不能讓你擁有充分利用多核 CPU 的效能,但他的好處是它的調度是虛擬機器層面的,確切地說就是可以由程式員自己來進行調度。greenlet 是 Python 界對 green thread 的一種比較好的實現。

如果使用 gevent 寫一個簡單的 echo 伺服器,大概是這樣子的:


可以看到有一個 echo 函數,它處理每一個用戶端串連,它讀一行、寫一行的方式來實現 echo 業務。大家可以看到代碼還是有點長。類似 gevent 的項目還有沈崴的 eurasia,http://code.google.com/p/eurasia 。

談完了 I/O,接下來有必要看一下協議方面,因為頁遊對網路通訊協定的處理還是頗有些要求的。這方面我比較推薦 google protobuf,這是一門協議描述語言,官方支援產生 C++/java/Python 的代碼,有許多第三方外掛程式可以產生其它語言的代碼。通過 protobuf 可以很方便地描述業務協議,比如登陸的時候需要有 username 和 password,以及可選的 timestamp 之類的,protobuf 能夠協助你去做序列化和還原序列化的工作。protobuf 還支援聲明 RPC,也就是 service,這個特效能讓大家方便地實現 RPC。我們也做了一套,就是 abu.rpc,它是基於 gevent 加 protobuf 來實現的。得益於 gevent,它提供了同步的 API,即當調用 RPC 的時候,就像調用普通函數一樣,等待返回就可以了,無需回調。得益於 protobuf,它是一個二進位協議,所以每個資料包都有較小的尺寸。libevent 是一個高效的非同步 I/O 庫,所以 abu.rpc 也很快。不過 abu.rpc 最重要的兩個特點是並行管線和雙向調用。所謂雙向調用就是指用戶端可以調用伺服器端,而伺服器端也可以調用用戶端提供的服務;也就是說用戶端也是可以有服務的,它可以在建立的串連上綁定自己的服務。所謂的並行管線是這樣的:


有時候用戶端會發起一個比較重量級的、比較耗時的請求,而後又發起一個較輕量的請求。如果沒有並行管線的支援,那麼雖然輕量級的請求很快就處理完了,但用戶端也只能等到重量級的請求完成以後才能收到輕量級的請求的處理結果,如左。這樣輕量級的請求就為別的請求所累,回應時間就變長了。如果有並行管線的機制,當輕量級的請求發過來時,經過簡單的計算,馬上就能夠返回結果,就有更快的響應,更好的即時性。大家再來看一下使用 abu.rpc 的 echo 伺服器:


可以看到代碼比直接使用 gevent 還是變短了不少的,複雜的地方可能是需要聲明 service 吧。

今天上午周琦(ZoomQuiet)提到使用 rabbitMQ 來解耦,的確,MQ 挺適合在應用(進程)間的,他提到的面向訊息編程其實大概可以說就是發布訂閱模式:我對什麼東西感興趣,到時候你就推送給我。現在大家都比較關注進程之間的 MQ,但其實在進程之內、模組之間,也是極其需要“MQ”的,所以我們實現了一個叫 message 的模組。可以訂閱感興趣的主題,當有這樣的主題發布時,訂閱的回調就會被調用到了。


中右側就是輸出。通過 context 可以對訊息處理流程做簡單的幹涉,比如某個訂閱者處理完了認為別的函數都沒有必要再調用之類,那麼可以使用 context 來終止它。主要是受到 falcon 語言的啟發而編寫的,falcon 有豐富的語言特性,比如面向訊息編程這個詞,我第一次見就是在 falcon 程式設計語言的手冊裡看到的。關於這個庫,我之前有寫過一個 slide,放在這裡:http://www.slideshare.net/laiyonghao/pythonmessage010 。在我們的《天下盛境》項目中,我們將其應用於任務、郵件以及好友等子系統中。舉個任務子系統的例子,比如完成任務需要殺死 5 只怪物,針對這麼多玩家做輪詢的話是比較麻煩的,但通過訂閱“怪物死亡”的主題,就可以在合適的時機去判定任務是否已經完成了,從而達到模組與模組間比較好的解耦的效果。

最後,給大家介紹一個簡單但又很難歸類的庫。在遊戲中,需要大量處理二進位的資料,這些資料通常由不同的平台、作業系統產生或儲存,比如在 32 位機上進行開發,但運營部署是在 64 位機器上,在 py2.6 的環境開發,在 py2.7 的環境部署,等。這時候往往產生一些相容性的問題,這類問題很難查出真正的原因。比如內建函數 hash() 在 32 位機器上返回的是 32 位的有符號整數,在 64 位機器上返回 64 位的有符號數,如果兩台機器需要比對雜湊結果,稍加不注意就可能會出問題,解決問題分分鐘需要兩個晚上都很常見,因為代碼沒有任務地方出錯,但邏輯全亂了套。因為我們在做用戶端與伺服器端的通訊加密時也是使用 Python 去實現,所以遇到了不少類似的問題。後來我們總結出需要一系列絕對地返回 32 位帶正負號的整數的函數,所以我們編寫了這個 absolute32 程式庫。它很簡單,只是對標準庫的幾個函數進行了封裝,提供了 hash/add/crc/adler 等函數。以 add 為例,它對溢出的的處理是與 C 語言一樣的,而不是像 Python 那樣自動轉換為 long 類型。這個庫的幾個函數我們在 py2.6/py3.1 和 32bit/64bit ubuntu 是進行了交叉測試,可以很好的簡單我們的相容性問題。

以上就是我今天要介紹的內容,謝謝大家。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.