為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

編程語言 CPU MMORPG Java 微軟 西部遊星 2018-11-30
為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

遊戲也分不同領域,不同的遊戲之間業務邏輯和適用架構區別很大,並不能一概而論。

比如對於大部分手遊、頁游來說,追求短平快的開發節奏也不要求太高的實時性和計算效率,C++在這些領域的使用屬於殺雞用牛刀。國內這些領域還採用 C++ 的團隊,要麼是技術決策者視野狹窄;要麼是大廠成熟團隊已有完善的遺留技術棧、工具鏈和人才儲備,遷移到其他語言的收益相對不高,或是怕擔轉型決策風險等等;再有就是從大廠出去創業順走了技術框架或迷信大廠經驗的團隊等。

題主特別提到 MMORPG ,此處就 MMORPG 這一領域為何普遍使用 C++ 進行簡單討論。

MMORPG主要是指在地圖上實時戰鬥一類(比如 WOW、傳奇等),不包括回合制 MMORPG (神仙道、夢幻西遊等)。

為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

常見 MMORPG 服務器在技術層面的特性需求:

  • 網絡IO密集。高頻率的視野同步消息(一般在 10-60Hz 之間),與玩家數量的關係是 O(n^2) 的複雜度,對於一些側重國戰等玩法的 MMORPG 尤其壓力山大。通常都需要配合相關視野管理算法來減少消息發包數量,甚至需要配合架構做廣播的負載分流。
  • CPU密集。MMORPG 的玩法規則都需要服務器做權威性的計算,簡單些的也需要大量怪物的 AI 和尋路計算,以及實時戰鬥的邏輯和技能運算等等;一些先進的 3D MMORPG 服務器甚至整合了物理引擎,來做碰撞檢測和校驗。
  • 實時性。此類遊戲側重實時戰鬥和交互體驗,能容忍的響應延遲通常在 200ms 以內,即使可以通過客戶端預演算進行緩和。考慮到網絡延遲這個不能通過語言和架構來解決的要素,兩次遊戲邏輯更新發包的間隔最好控制在幾十毫秒這一量級。(所以一些 GC 不太注重實時性的語言,可能會有潛在的負面體驗影響)。
  • 穩定性和容災。常 Crash 的服務器,輕則影響玩家體驗,重則導致公司倒閉。
  • 開發效率。這個方面除了受語言特性本身影響,還需要考量其它要素,比如生態圈豐富程度(需要的功能可以容易找到穩定好用的庫)、周邊工具鏈完善程度、人員補充難易程度(是否是學校培訓的主力語言、是否是領域比較主流的語言,或者是否足夠簡單好培訓)、現有遺留人力和技術資源的價值等等。
為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

C++ 和其它候選語言的比較

C++:

  • 網絡 IO:歷史上這方面曾經是考量的主要因素,近年來幾乎所有主流後端語言都封裝有高效的網絡 IO 庫,C++ 已不具備獨特優勢。
  • CPU 利用率:C++ 在這方面的優勢不需要討論了吧...
  • 實時性:無 GC,內存分配延遲可控(內存池、預分配等),毫秒級延遲需求的高頻交易都在用。
  • 穩定性和容災:用 C++ 寫出長期穩定運行的服務器程序,對開發團隊而言是件要求比較高的事情,尤其在邏輯複雜又變更頻繁的前提下。語言本身也不保證內存訪問的安全性,如果有內存寫越界導致的 Crash 也很難定位。國內某大廠採用了分離數據和邏輯進程,通過進程間共享內存來通信的方式,來實現邏輯進程崩潰重啟不丟失數據。不過這種做法有一定門檻,存在性能開銷,而且對開發效率和靈活性也有比較大的約束,也不易整合第三方庫,不能算是通用的最佳實踐。
  • 開發效率:如果有良好的內力和 C++ 編程素養,並且配合現代 C++ 的一些語法(auto、lambda、智能指針等),開發效率尚可算是勉強及格,但相對以下討論的其他語言來說仍處於劣勢,然而達到上述水準的人力資源成本卻要比其它語言要高出不少(人員補充速度、培訓週期和薪資)。綜合而言,這方面可算 C++ 的一大短板。

那麼,假設不採用混合語言的方案(C++ 配合 Lua 或 Python,或者多服架構不同服務器用不通語言 等),除了 C++ 之外還有哪些語言值得考慮?

考慮到 MMORPG 在 CPU 計算方面的壓力,解釋型語言暫且可以排除。

目前考察過的備選方案,主要有 Java、C#、Go、Rust。

為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

Java:

優點:

  • 生態圈成熟,庫豐富。
  • Netty 網絡庫性能強悍。
  • 不爽語法還可以用 scala 和 kotlin...

缺點:

  • 除了原始類型外,不支持自定義值類型。而且泛型是以類型擦除的方式實現。這樣的特性導致了:1.難以把數據連續緊湊地進行表示來優化算法的緩存命中率,比如2D地圖的每個格子座標都是個object,尋路算法呵呵。3D 場景的碰撞體每個頂點都是個object,物理引擎呵呵。2.對原本對實時性不甚友好的 GC 造成了更大壓力。
  • 成熟的 JVM 實現並不怎麼側重 GC 的實時性。如果觸發了百毫秒以上的世界凍結 GC 延遲,所有在線玩家都會受到影響。
  • JIT 在預熱不足的情況下,偶爾會導致性能曲線不平滑,引入預料之外的響應延遲。

C#:

優點:

  • 開發友好,語法糖甜。
  • 有真正的泛型和值類型。特定算法好優化。

缺點:

  • 微軟家的。微軟家的。微軟家的。跑在 Windows Server 下沒什麼問題,然而拋開授權費不談,大部分主流的開源好物都是優先考慮 Unix / Linux,比如 Redis(長期沒有 Windows 版本的官方支持)、MongoDB(Windows 下性能要弱於 Linux 下),而且 Windows Server 的網絡性能也要弱一些。除非解決方案都用微軟全家桶,不然部署和運維就需要同時維護兩個平臺...至於 Mono,跟 JVM 比起來就像玩具。只能期待 Rosalyn 成熟了。(目前項目正在用 .Net Core,實現遊戲邏輯跑在Linux下問題不大,一些跟操作系統聯繫比較緊密的底層功能還是用了C++)
  • GC 實時性類似 Java。
為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

Go:

優點:

  • 語法簡單易掌握。
  • 開發體驗友好。
  • 有值類型。
  • 新版本的 Go,GC 實時性良好(1.8 號稱 STW 控制在 1ms 以內)。

缺點:

  • 沒有範型,某些地方需要轉型成 interface{},不過編譯器會做逃逸分析,不必要的地方不會自動 boxing,影響不算太嚴重。

Rust:

優點:

  • 運行效率比肩 C++。
  • 語言特性優秀。
  • 編譯期保證了內存安全,沒有 GC 開銷。
  • 編譯期保證線程安全,可以放心大膽地併發,容易寫出高效的多線程代碼(不過死鎖是需要自己避免的)。

缺點:

  • 上手曲線較陡。
  • 太年輕,生態圈尚未成熟。
  • 較小眾,人員補充困難。
為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

大部分 MMORPG 主要採用 C++ 並不是沒有原因 ,雖然歷史原因的比重不小。然而如果要在什麼都沒有的情況下,從零開始開發 MMORPG 服務器,採用 C++ 並無必要。拋開人才儲備的方面不談,Go 算是目前開發 MMORPG 服務器各方面特性都比較匹配的選擇:無論開發效率還是運行效率,以及工具和人員培訓速度等等。如果是技術導向的團隊,可以試試 Rust。C# 和 Java 也是不錯的選擇,雖然有些特性不是很好滿足,但也足夠支撐一款遊戲成功了(如果不追求提供極致的平滑體驗的話)。

至於 C++,在具備一些前提條件的情況下可以考慮採用:已有成熟 C++ MMORPG 代碼框架;已有 C++ 寫得 666 的技術團隊;不差錢也不趕進度,就要質量稍高一些的流暢體驗;需要整合一些 C++ 庫等。不過即使如此,C++ 也推薦搭配其它語言使用(比如早幾年常見搭配 Lua,主要用來提高迭代速度和開發效率,並且一定程度上可以支持熱更)。

為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

目前幾乎沒有純粹的 C/C++開發遊戲服務端的。

早年開發遊戲必須用C++,這沒得說,2000-2004年,java還沒有nio,其他動態語言不抗重負,只能C/C++能開發出完整可用的遊戲服務端。直到2005年,韓國的遊戲很多都還是純C++寫服務端,金山之前也開發過很多純粹C++的遊戲服務端,後來大家都切了。

現代選擇有很多:java + javascript, c+python, c+lua, scala, go, erlang。面向性能的服務器用 java,面向邏輯服務器 python,面向高併發的會選擇 scala,次一級高併發或者性能測試程序(機器人)會選擇 gevent。那是不是就不用C++呢?用 C來做網絡,不用C++,但是C的比例在所有代碼中佔比有限。

這是否意味可以放棄C/C++了?也不是:C語言是一把鋒利的匕首,而現代動態語言是一把長劍。平時匕首可以藏在身上,大部分時候用長劍披荊斬棘就夠了,但當碰到堅硬的石頭,長劍不管用了,那麼拿出匕首來果斷的切碎他。

對於一個成熟領域而言,建議是儘量用更高級一點的開發語言,因為遊戲開發很多核心技術都有了較為妥當的解決方法。大量的服務端邏輯其實都是在等待,等待網絡,等待數據庫,這種情況下用C得不償失。但是服務端有一些地方還是躲不開C/C++,比如當服務器涉及到 3D計算的話(國內很多2D服務端,國外很多3D服務端),大量的矢量矩陣,除了用C++封裝出一套好用的數學庫外,即便直接用java寫,那也是很麻煩的。再比如現在快速動作越來越多,為了讓玩家操作更流暢,需要基於 UDP快速可靠協議,協議開發用 java或者scala,性能上是沒辦法滿足要求的,況且協議實現後要和客戶端通信,沒法讓所有客戶端跟著一起用java/scala。再比如某些cpu密集的抽象度高的模塊,如 aoi或者 ai模塊。

對於一個新興領域而言,C/C++很多情況下是別無選擇的東西。比如移動化浪潮剛起步的時候,還沒有啥 cocos或者 unity真要開發遊戲,必須迅速的使用起 OpenGL ES和 OpenSL,然後再疊加某一腳本,以快制勝,第一批移動浪潮上發財的就是這些遊戲。又或者,可以根本躲開,先不介入,等到幾年後cocos和 unity成熟了,在介入用lua / C#寫程序。再比如服務端如果離開熟悉的遊戲和web,去開發一個陌生的領域,如流媒體服務,會發現這怎麼和10年前的遊戲一樣呀,什麼高級工具都不給用用,這時可以再等個四五年應該高級工具會出現,異或想領先別人時,就果斷的拿出 C/C++來解決之,這就是C獨有的開拓新領域能力。

大部分答案都是非黑即白,非此即彼。不要只會C不會動態語言,避免成為一個傻逼;也不要只會動態語言不會C,避免離開熟悉的溫室就活不下去。對於一個新手而言,如果什麼都沒學過,建議是先用快速開發的東西,把項目弄起來再說,有精力有機會的情況下,也不能完全放棄一些基礎的東西,讓自己殘缺了。

PS:在相同架構下,就純粹性能而言,各種語言性能差距到底是多少呢?如果只開發回合制這些慢節奏遊戲,或者HTTP接口,大部分情況都在等待數據庫等待用戶消息的話,差別確實不大,的確可能5%都不到。如果cpu密集了,那麼可以參考下面的圖表,總體來說是10-50倍的性能差別:

為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

有人問,說了半天,這個也不行,那個也不完美,而時間有限,有沒有一個更經濟實惠的方法呀?如何才一次性達到彼岸呀?時間有限項目吃緊有沒有更好的選擇?說有!那就是 java。國內遊戲開發繞來繞去還是腳本+C+erlang+go,難道大家就不會其他東西了麼?大部分可以的情況下,除了非用C/C++,推薦各位認真考慮下 java,這個性能上最接近C的東西,能承當大部分cpu密集型事務,卻又不會象c那樣 crash了找都找不到問題在哪裡。同時面向高併發時基於原生jvm的 scala可以提供類似 erlang的簡單方式,函數式編程 & 大規模併發協程 & actor;同時 java可以很方便的同 javascript結合,js的速度應該是動態語言裡面最快的吧。再者 java還有 groovy,可以提供 python/ruby的泛型編程,用超高的開發效率和 python/ruby媲美,同時還能和 scala 結合實現高併發。最重要的是寫 java好招聘,到處都是寫 java的工程師,大部分語言級的培訓都可以省略了。

國內遊戲開發者很多拒絕學習 java,因為很多開發者自己是碰都沒碰過。現在拒絕 java的人,大部分只是在遊戲圈子裡面打轉的人,偶爾開發下 web,缺乏其他行業和領域的經驗。看看除遊戲外,當今多少世界級的開源服務器是用 java開發的?遊戲就真有那麼特殊麼?看不是,國外大把java開發的遊戲服務端,各位如果知道遊戲服務端領域有啥 java技術棧解決不了的事情,麻煩告訴一聲。再看看java上下游的 scala, javascript, groovy這些東西。所以建議各位,有空有條件的情況下,認真考慮下 java技術棧,世界很大,不是隻有遊戲;即便遊戲,現在的開發方法真的對嗎?

為何遊戲服務端用 C++ 來寫,是歷史原因還是性能方面的考慮?

相關推薦

推薦中...