Unity ECS(一)了解ECS與DOTS

本文轉(zhuǎn)自Unity Connect博主?EntherVarope

ECS是什么?可以做什么理疙?為什么ECS成為我的選擇?

什么是ECS(實(shí)體組件系統(tǒng))?

其實(shí)ECS的概念早就誕生了悯舟,但是它是因?yàn)槭赝蠕h才逐漸被人所知。(暴雪的守望先鋒是基于ECS模式設(shè)計(jì)的砸民,用于改善在大場(chǎng)景下多角色運(yùn)算的效率)

ECS是一種軟件架構(gòu)模式抵怎,由三個(gè)元素組成:實(shí)體(Entity),組件(Component)和系統(tǒng)(System)(看起來和MVC很相似)岭参。游戲程序分為這三個(gè)主要元素反惕,并且通過定義每個(gè)系統(tǒng)的責(zé)任和關(guān)系來管理游戲。

實(shí)體代表游戲世界中的事物演侯。實(shí)體本身沒有特定功能姿染,它們將會(huì)被組件填充來成為一個(gè)實(shí)體。

組件是附加到事物的數(shù)據(jù)秒际。重點(diǎn)不是對(duì)象悬赏,而是數(shù)據(jù)狡汉,沒有辦法操縱它。比如操作游戲的角色時(shí)闽颇,位置盾戴,速度和體力等每個(gè)狀態(tài)都將成為一個(gè)組成部分,并與稱為“角色”實(shí)體相關(guān)聯(lián)兵多。另外尖啡,實(shí)體中的字段信息也被表示為組件部分。

系統(tǒng)是游戲世界的法則中鼠。給定與實(shí)體關(guān)聯(lián)的某些組件作為數(shù)據(jù)輸入源可婶,或者更新某些組件的值(可能與輸入的組件相同)。隨著整個(gè)系統(tǒng)更新每一幀援雇,游戲世界也在不斷進(jìn)行矛渴。我認(rèn)為最容易想象的是物理定律。例如惫搏,想象一個(gè)剛體實(shí)體具温。它的運(yùn)動(dòng)基于利用位置和速度兩個(gè)分量的系統(tǒng)來更新坐標(biāo)。

粗略地說筐赔,系統(tǒng)負(fù)責(zé)處理铣猩,組件負(fù)責(zé)數(shù)據(jù),而實(shí)體是一組組的組件茴丰,用于過濾系統(tǒng)正在處理的內(nèi)容达皿。由于系統(tǒng)和數(shù)據(jù)是完全分開的,因此它與面向?qū)ο蟛患嫒荨?/p>

Unity也具有類似于ECS的架構(gòu)(自Unity2018.2起已提供ECS)贿肩。實(shí)體是已經(jīng)削減到極限的游戲?qū)ο蠊δ苈鸵M件是組件的序列化數(shù)據(jù)部分,其余部分是系統(tǒng)汰规。Unity ECS是對(duì)純ECS的改進(jìn)汤功。

ECS可以做什么?

UnityECS正在圍繞這一設(shè)計(jì)模式開發(fā)新的“面向數(shù)據(jù)技術(shù)堆椓锵”(DOTS),如果經(jīng)常關(guān)注Unity的發(fā)布會(huì)滔金,就或多或少對(duì)它有所了解。但是事先寫在前邊茂嗓,ECS并不能加速任何類型的游戲/程序餐茵。

ECS有望加速游戲的類型

彈幕游戲

有海量單位的大型RTS

開放世界/沙盒

集群模擬(例如新出的“動(dòng)物星球”)

此類具有大量“遵循同一運(yùn)算規(guī)則”對(duì)象的程序,便可以利用ECS來加速述吸。

為什么ECS成為我的選擇忿族?

答案很簡(jiǎn)單:因?yàn)樗值目欤⌒史浅V撸绕饌鹘y(tǒng)的面向?qū)ο缶幊坛澹鼘?duì)內(nèi)存的利用率是成幾何倍數(shù)的增長(zhǎng),還有一些其他的優(yōu)點(diǎn):

輕松并行化--------清晰的系統(tǒng)輸入輸出和小粒度

良好的緩存效率------通過順序訪問組件數(shù)組獲得空間局部性(動(dòng)態(tài)場(chǎng)景讀取十分方便)

耦合度低---------因?yàn)橄到y(tǒng)僅交換數(shù)據(jù)

易于測(cè)試---------因?yàn)橄到y(tǒng)沒有狀態(tài)

當(dāng)然ECS也有它自身的一些缺點(diǎn):

對(duì)于習(xí)慣了面向?qū)ο缶幊痰娜似佣粒枰淖兙幊趟季S模式

在Unity推出完善的工具集前屹徘,管理內(nèi)存是一件困難的事

至于為什么ECS如此之快,內(nèi)容比較多衅金,感興趣的可以繼續(xù)往下看噪伊,跳過也無妨。


傳統(tǒng)的Unity GameObject與組件工作流

在傳統(tǒng)的流程中氮唯,我們制作物體鉴吹,為其添加腳本。這種做法有一些固有的缺點(diǎn)和性能缺陷惩琉。首先豆励,數(shù)據(jù)和處理它們的方法是緊密耦合的,代碼重用率較低瞒渠。此外良蒸,系統(tǒng)非常依賴引用類型,引用錯(cuò)誤屢見不鮮伍玖。

最重要的是嫩痰,在上圖的示例中:Gun與Player所引用的Transform、Rigidbody窍箍、Collider等這些關(guān)鍵腳本被分散在堆內(nèi)存中串纺,數(shù)據(jù)將不會(huì)轉(zhuǎn)換成可由更快的SIMD(單指令多數(shù)據(jù)流)矢量單元進(jìn)行操作的形態(tài)。


游戲?qū)ο笠⑵湫袨榧捌浣M件之間分散的內(nèi)存引用

上圖顯示了這種數(shù)據(jù)存儲(chǔ)方法的隨機(jī)偶發(fā)性質(zhì)纺棺。每一個(gè)單引用,在使用時(shí)都有可能會(huì)將其所有的成員變量從系統(tǒng)內(nèi)存中全部拉出晰搀,舉個(gè)例子五辽,當(dāng)我命令Gun進(jìn)行開火,子彈飛出外恕,對(duì)子彈的坐標(biāo)進(jìn)行運(yùn)算讓它飛行杆逗,表面上看起來僅僅是對(duì)子彈這個(gè)對(duì)象的Transform中的position進(jìn)行了操作,但實(shí)際上鳞疲,子彈的rotation罪郊,gameobject屬性,還有等等等等其他成員也一并拉出來操作了尚洽。


綠色項(xiàng)目表示實(shí)際用于移動(dòng)操作的成員悔橄,其余都是浪費(fèi)空間

綠色塊表示開發(fā)想象中認(rèn)為操作引用的成員,而實(shí)際上,硬件聽從腳本的命令從內(nèi)存中獲取數(shù)據(jù)時(shí)癣疟,緩存中會(huì)填充許多無用的數(shù)據(jù)(紅色的塊)挣柬,如果將為要移動(dòng)的GameObject設(shè)置成一個(gè)獨(dú)立的只有位置與旋轉(zhuǎn)成員的矩陣,那么系統(tǒng)就能夠在很短的時(shí)間內(nèi)執(zhí)行操作睛挚。

在ECS中困后,整個(gè)的流程將會(huì)是:


具有JobSystem的ECS

只需要考慮每一種GameObject所包含的數(shù)據(jù)實(shí)體则酝,而不用考慮自己的組件集合(拋棄了Transfrom疏橄,Rigidbody等)伟叛,將處理與各個(gè)對(duì)象類型完全分離。實(shí)體僅僅是一個(gè)句柄(或者說是一個(gè)標(biāo)識(shí)符)永遠(yuǎn)索引它表示的不同數(shù)據(jù)類型的集合(ComponentDataGroups)系統(tǒng)可以通過這些句柄來對(duì)所有組件進(jìn)行過濾和操作淤击,而不需要將系統(tǒng)與實(shí)體類型明確結(jié)合匠抗。這種工作機(jī)制有很大優(yōu)勢(shì),它不僅能提高緩存效率污抬,縮短訪問時(shí)間汞贸,它還支持現(xiàn)代CPU中的使用數(shù)據(jù)對(duì)齊的先進(jìn)技術(shù)(自動(dòng)矢量化 即:SIMD),這種技術(shù)帶來的效率提升是極為可觀的壕吹。在Unity的DOTS中著蛙,還可以使用Brust Complier跳過中間語言的編譯,使得性能進(jìn)一步的提升耳贬。

關(guān)于數(shù)據(jù)對(duì)齊與SIMD


傳統(tǒng)的內(nèi)存塊與進(jìn)行了數(shù)據(jù)對(duì)齊的ECS內(nèi)存塊

實(shí)際編程中踏堡,對(duì)內(nèi)存的管理總是不可能達(dá)到完美利用,總會(huì)有或多或少的內(nèi)存塊處于閑置狀態(tài)咒劲,閑置內(nèi)存不僅沒有任何用處顷蟆,系統(tǒng)仍然要訪問它們?cè)龃笤L問開銷(浪費(fèi)時(shí)間)。傳統(tǒng)的面向?qū)ο笙码m然降低抽象門檻了腐魂,但是對(duì)內(nèi)存來說實(shí)際上是很不友好的(構(gòu)建對(duì)象時(shí)帐偎,數(shù)據(jù)引用總是雜亂無序的)。面向數(shù)據(jù)編程將數(shù)據(jù)提取出來蛔屹,不用關(guān)心他們實(shí)際上的聯(lián)系削樊,僅僅是由實(shí)體這個(gè)索引來引用,這就代表兔毒,對(duì)于同類型的數(shù)據(jù)漫贞,可以將他們放在同一個(gè)內(nèi)存塊里,無論是對(duì)內(nèi)存的利用或者是系統(tǒng)的訪問都是十分便利的育叁。

(PS:就算是數(shù)據(jù)對(duì)齊了迅脐,也不能徹底消除閑置內(nèi)存,但是比起傳統(tǒng)的內(nèi)存結(jié)構(gòu)來說豪嗽,閑置內(nèi)存的數(shù)量會(huì)大為減星疵铩)豌骏。

SMID:

SIMD全稱Single Instruction Multiple Data,單指令多數(shù)據(jù)流隐锭,能夠復(fù)制多個(gè)操作數(shù)窃躲,并把它們打包在寄存器的一組指令集。

傳統(tǒng)的CPU使用SISD來完成邏輯運(yùn)算钦睡,過程可以籠統(tǒng)的概括為一個(gè)執(zhí)行單元先訪問內(nèi)存框舔,根據(jù)命令找到第一個(gè)操作數(shù),再一次訪問內(nèi)存赎婚,找到第二個(gè)操作數(shù),才能根據(jù)命令進(jìn)行邏輯運(yùn)算(在查找操作數(shù)的過程中樱溉,由于數(shù)據(jù)的引用是雜亂無序的挣输,執(zhí)行單元只能遍歷每一個(gè)內(nèi)存塊,這就造成了性能瓶頸)福贞。

新世代的CPU所采用的SIMD則是由數(shù)個(gè)執(zhí)行單元同時(shí)訪問內(nèi)存撩嚼,一次性找到所需的操作數(shù)進(jìn)行運(yùn)算,事實(shí)上挖帘,由于進(jìn)行了數(shù)據(jù)對(duì)齊完丽,每一個(gè)執(zhí)行單元查找內(nèi)存的效率比SISD的查找要高出不少,這就好比將無數(shù)的快遞按照地區(qū)分門別類拇舀,一旦CPU發(fā)出“拿出上海地區(qū)的快遞“指令逻族,每一個(gè)快遞員(執(zhí)行單元)都會(huì)直奔存放上海快遞的貨架而不用一個(gè)貨架一個(gè)貨架的搜索骄崩。這樣的特性非常適合大數(shù)據(jù)運(yùn)算聘鳞。


SISD與SIMD

以上內(nèi)容都是關(guān)于ECS本身的優(yōu)勢(shì),接下來將闡述Unity基于ECS進(jìn)一步開發(fā)的面向數(shù)據(jù)技術(shù)棧工具DOTS要拂。

UnityDOTS(Data-Oriented Technology Stack)

Burst Complier

爆發(fā)式編譯器(抠璃?)

爆發(fā)編譯器是UnityECS為了更高效地組織數(shù)據(jù)所產(chǎn)生的后臺(tái)性能增益開發(fā)的。從本質(zhì)上講脱惰,突發(fā)編譯器將根據(jù)玩家設(shè)備上的處理器功能優(yōu)化代碼操作搏嗡。例如,您可以通過填充未使用的寄存器來執(zhí)行 16拉一、32 或 64次浮點(diǎn)預(yù)算采盒,而不是一次只進(jìn)行 1 次浮點(diǎn)運(yùn)算。

新的編譯器技術(shù)基于 Unity 的新數(shù)學(xué)命名空間(Unity.mathematics)和 C# 作業(yè)系統(tǒng)(JobSystem)以及改進(jìn)過的高性能C#(HPC)舅踪,基于系統(tǒng)知道數(shù)據(jù)已經(jīng)通過實(shí)體組件系統(tǒng)正確設(shè)置的事實(shí)纽甘。英特爾 CPU 的當(dāng)前版本支持英特爾? SIMD 流指令擴(kuò)展 4(英特爾? SSE4)、英特爾? 高級(jí)矢量擴(kuò)展指令集 2(英特爾? AVX2)以及用于浮點(diǎn)和整數(shù)的英特爾? 高級(jí)矢量擴(kuò)展指令集 512(英特爾? AVX-512),AMD的支持3D Now的CPU等都是能支持爆發(fā)式編譯器的(除非是在十分老舊的電腦上運(yùn)行抽碌,否則不需要考慮兼容性問題悍赢,因?yàn)樽詣?dòng)矢量化技術(shù)已經(jīng)成為現(xiàn)在與未來的CPU主流標(biāo)準(zhǔn))决瞳。該系統(tǒng)還支持在每種方法中使用不同的精確度,以過渡方式應(yīng)用左权。例如皮胡,如果您在低精度的頂級(jí)方法內(nèi)使用余弦函數(shù),則整個(gè)方法也將使用余弦的低精度版本赏迟。該系統(tǒng)還根據(jù)當(dāng)前運(yùn)行游戲的處理器的功能支持屡贺,通過動(dòng)態(tài)選擇適當(dāng)?shù)膬?yōu)化功能為 AOT(前期)編譯做準(zhǔn)備。

這種編譯器的另一個(gè)優(yōu)勢(shì)是確保游戲的未來適用性锌杀。如果一款全新的處理器產(chǎn)品線上市甩栈,其中包含一些令人驚嘆的新功能,Unity 可以在后臺(tái)為您完成所有費(fèi)力工作糕再。只需對(duì)編譯器進(jìn)行升級(jí)量没,以獲取優(yōu)勢(shì)。編譯器是基于軟件包的突想,無需 Unity 編輯器更新即可升級(jí)殴蹄。該爆發(fā)式編譯器軟件包將以自己的節(jié)奏進(jìn)行更新,因此您將能夠利用最新的硬件架構(gòu)改進(jìn)和功能猾担,而無需等待代碼升級(jí)到下一個(gè)編輯器版本袭灯。

C#JobSystem

C#作業(yè)系統(tǒng)

大多數(shù)使用多線程代碼和通用任務(wù)系統(tǒng)的人都知道編寫線程安全代碼很難。線程爭(zhēng)用情況雖然很罕見绑嘹,但仍然可能會(huì)發(fā)生稽荧。如果編程員沒有想到這個(gè)問題,可能會(huì)導(dǎo)致潛在的程序嚴(yán)重錯(cuò)誤工腋。除此之外蛤克,上下文切換的成本,Debug的成本很高夷蚊,因此學(xué)習(xí)如何平衡工作負(fù)載以盡可能高效地跨核心運(yùn)行是很困難的构挤。最后,編寫 SIMD 優(yōu)化代碼或 SIMD 內(nèi)聯(lián)函數(shù)是一種深?yuàn)W的技能惕鼓,有時(shí)最好交給編譯器去完成筋现。新的 Unity C# 作業(yè)系統(tǒng)為您解決所有這些難題,以便您可以在現(xiàn)代 CPU 中放心地使用所有可用的內(nèi)核和 SIMD 矢量化箱歧。

總而言之矾飞,C#的JobSystem提供一系列的多線程解決方案,讓編寫多線程程序更為安全方便呀邢。


傳統(tǒng)的Unity程序如果不使用外部程序集執(zhí)行的是單線程

常規(guī)的Unity如果要開發(fā)多線程洒沦,不僅要引入外部的實(shí)現(xiàn)方式,Debug過程也是繁瑣不可視的价淌,而引入C#JobSystem申眼,可以讓系統(tǒng)智能化管理安排多線程任務(wù)瞒津,使用Unity自身封裝的多線程安全集合(例如:NativeArray<>)可以有效防止線程沖突的問題。


使用C#JobSystem來安排任務(wù)至每一個(gè)核心

在接下來的文章中括尸,我會(huì)告訴你如何利用DOTS來編寫一個(gè)ECS程序巷蚪。

原文鏈接:https://connect.unity.com/p/unityecs-yi?app=true

戳上方鏈接下載官方app即可提前了解接下來的文章,還有技術(shù)社區(qū)在線答疑濒翻,更多學(xué)習(xí)資源等你來發(fā)現(xiàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屁柏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子有送,更是在濱河造成了極大的恐慌淌喻,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雀摘,死亡現(xiàn)場(chǎng)離奇詭異似嗤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)届宠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乘粒,“玉大人豌注,你說我怎么就攤上這事〉破迹” “怎么了轧铁?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)旦棉。 經(jīng)常有香客問我齿风,道長(zhǎng),這世上最難降的妖魔是什么绑洛? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任救斑,我火速辦了婚禮,結(jié)果婚禮上真屯,老公的妹妹穿的比我還像新娘脸候。我一直安慰自己,他們只是感情好绑蔫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布运沦。 她就那樣靜靜地躺著,像睡著了一般配深。 火紅的嫁衣襯著肌膚如雪携添。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天篓叶,我揣著相機(jī)與錄音烈掠,去河邊找鬼羞秤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛向叉,可吹牛的內(nèi)容都是我干的锥腻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼母谎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瘦黑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奇唤,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤幸斥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后咬扇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甲葬,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年懈贺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了经窖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梭灿,死狀恐怖画侣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堡妒,我是刑警寧澤配乱,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站皮迟,受9級(jí)特大地震影響搬泥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伏尼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一忿檩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爆阶,春花似錦休溶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至徒役,卻和暖如春孽尽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忧勿。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工杉女, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞻讽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓熏挎,卻偏偏與公主長(zhǎng)得像速勇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坎拐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容