小編給大家分享一下Unity中DOTS要實(shí)現(xiàn)的特點(diǎn)有哪些,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
專注于為中小企業(yè)提供網(wǎng)站設(shè)計(jì)、做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)丹江口免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了數(shù)千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
DOTS 要實(shí)現(xiàn)的特點(diǎn)有:
性能的準(zhǔn)確性。我們希望的效果是:如果循環(huán)因?yàn)槟承┰驘o(wú)法向量化(Vectorization,可以參考 StackOverflow 的問(wèn)題),它應(yīng)該會(huì)出現(xiàn)編譯器錯(cuò)誤,而不是使代碼運(yùn)行速度慢8倍,并得到正確結(jié)果,完全不報(bào)錯(cuò)。
跨平臺(tái)架構(gòu)特性。我們編寫(xiě)的輸入代碼無(wú)論是面向 iOS 系統(tǒng)還是 Xbox,都應(yīng)該是相同的。
我們應(yīng)該有不錯(cuò)的迭代循環(huán)。在修改代碼時(shí),可以輕松查看為所有架構(gòu)生成的機(jī)器代碼。機(jī)器代碼“查看器”應(yīng)該很好地說(shuō)明或解釋所有機(jī)器指令的行為。
安全性。大多數(shù)游戲開(kāi)發(fā)者不把安全性放在很高的優(yōu)先級(jí),但我們認(rèn)為,解決Unity出現(xiàn)內(nèi)存損壞問(wèn)題是關(guān)鍵特性之一。在運(yùn)行代碼時(shí)應(yīng)該有一個(gè)特別模式,如果讀取或?qū)懭氲絻?nèi)存界限外或取消引用Null時(shí),它能夠提供我們明確的錯(cuò)誤信息。
當(dāng)我們使用 C# 語(yǔ)言時(shí),仍然無(wú)法控制數(shù)據(jù)在內(nèi)存中如何進(jìn)行分布,但這是我們提升性能的關(guān)鍵點(diǎn)。
除此之外,標(biāo)準(zhǔn)庫(kù)面向的是“堆上的對(duì)象”和“具有其它對(duì)象指針引用的對(duì)象”。
也就是意味著,當(dāng)處理性能敏感代碼時(shí),我們可以放棄使用大部分標(biāo)準(zhǔn)庫(kù),例如:Linq、StringFormatter、List、Dictionary。禁止內(nèi)存分配,即不使用類,只使用結(jié)構(gòu)、映射、垃圾回收器和虛擬調(diào)用,并添加可使用的部分新容器,例如:NativeArray 和其他集合類型。
我們可以在越界訪問(wèn)時(shí)得到錯(cuò)誤和錯(cuò)誤信息,以及使用 C++ 代碼時(shí)的調(diào)試器支持和編譯速度。我們通常把該子集稱為高性能 C# 或 HPC#。
它可以被總結(jié)為:
大部分的原始類型(float、int、uint、short、bool…),enums,structs 和其他類型的指針
集合:用 NavtiveArray<T>
代替 T[]
所有的控制流語(yǔ)句(除了 try、finally、foreach、using)
對(duì) throw new XXXException(...)
給予基礎(chǔ)支持
Unity 構(gòu)建了名為 Burst 的代碼生成器和編譯器。
Burst 有時(shí)運(yùn)行速度比 C++ 快,有時(shí)也會(huì)比 C++ 慢。后面的情況源于性能問(wèn)題,Unity 已經(jīng)開(kāi)始著手解決。
當(dāng)使用 C# 時(shí),我們對(duì)整個(gè)流程有完整的控制,包括從源代碼編譯到機(jī)器代碼生成,如果有我們不想要的部分,我們會(huì)找到并修復(fù)它。我們會(huì)逐漸把 C++ 語(yǔ)言的性能敏感代碼移植為 HPC# 代碼,這樣會(huì)更容易得到想要的性能,更難出現(xiàn) Bug,更容易進(jìn)行處理。
如果 Asset Store 資源插件的開(kāi)發(fā)者在資源中使用 HPC# 代碼,資源插件在運(yùn)行時(shí)代碼會(huì)運(yùn)行得更快。除此之外,高級(jí)用戶也會(huì)通過(guò)使用 HPC# 編寫(xiě)出自定義高性能代碼而受益。
ECS Track: Deep Dive into the Burst Compiler - Unite LA
Burst 對(duì)于 HPC# 更詳細(xì)的支持可以在下面找到:
Burst User Guide
C++ 和 C# 都無(wú)法為開(kāi)發(fā)者編寫(xiě)線程安全代碼提供太多幫助。即使在今天,擁有多個(gè)核心游戲消費(fèi)級(jí)硬件發(fā)展至今已經(jīng)過(guò)去了十年,但依舊很難有效處理使用多個(gè)核心的程序。
數(shù)據(jù)沖突,不確定性和死鎖是使多線程代碼難以編寫(xiě)的挑戰(zhàn)。Unity 想要的特性是“確保代碼調(diào)用的函數(shù)和所有內(nèi)容不會(huì)在全局狀態(tài)下讀取或?qū)懭搿?。Unity 希望應(yīng)該讓編譯器拋出錯(cuò)誤來(lái)提醒,而不是屬于“程序員應(yīng)遵守的準(zhǔn)則”,Burst 則會(huì)提供編譯器錯(cuò)誤。
Unity 鼓勵(lì) Unity 用戶編寫(xiě) “Jobified” 代碼:將所有需要發(fā)生的數(shù)據(jù)轉(zhuǎn)換劃分為 Job。
每個(gè) Job 都具有“功能性”,因?yàn)?Job 沒(méi)有副作用。 Job 會(huì)明確指定使用的只讀緩沖區(qū)和讀寫(xiě)緩沖區(qū),嘗試訪問(wèn)其它數(shù)據(jù)會(huì)出現(xiàn)編譯器錯(cuò)誤。
Job 調(diào)度程序會(huì)確保在 Job 運(yùn)行時(shí),任何程序都不會(huì)寫(xiě)入只讀緩沖區(qū)。我們會(huì)確保在 Job 運(yùn)行時(shí),任何程序都不會(huì)讀取讀寫(xiě)緩沖區(qū)。
如果調(diào)度的 Job 違反了這些規(guī)則,我們會(huì)得到運(yùn)行時(shí)錯(cuò)誤。這種錯(cuò)誤不僅在競(jìng)態(tài)條件下得到,錯(cuò)誤信息會(huì)說(shuō)明,你正在嘗試調(diào)度的 Job 想要讀取緩沖區(qū) A,但你之前已經(jīng)調(diào)度了會(huì)寫(xiě)入緩沖區(qū) A 的 Job ,所以如果想要執(zhí)行該操作,需要把之前的 Job 指定為依賴。
由于能夠處理所有組件,我們可以使這些組件了解各自的存在。例如:向量化(Vectorization)無(wú)法進(jìn)行的常見(jiàn)情況是,編譯器無(wú)法確保二個(gè)指針不指向相同的內(nèi)存,即混淆情況(Alias)。
而兩個(gè)集合庫(kù)中的 NativeArray 從不會(huì)混淆,我們可以在 Burst 中運(yùn)用這個(gè)知識(shí),使它不會(huì)由于害怕兩個(gè)數(shù)組指針指向相同內(nèi)存而放棄優(yōu)化(Alias)。Alias 的問(wèn)題在 Unity GDC 中也有一個(gè)演講提到過(guò):Unity at GDC - C# to Machine Code
Unity 還編寫(xiě)了 Unity.Mathemetics 數(shù)學(xué)庫(kù),提供了很多像 Shader 代碼的數(shù)據(jù)結(jié)構(gòu)。Burst 也能和這數(shù)學(xué)庫(kù)很好的工作,未來(lái) Burst 將能夠?yàn)?nbsp;math.sin()
等計(jì)算作出犧牲精度的優(yōu)化。
對(duì)于 Burst 而言,math.sin()
不僅是要編譯的 C# 方法,Burst 還能理解出 sin()
的三角函數(shù)屬性,同時(shí)知道 x 值較小時(shí)會(huì)出現(xiàn) sin(x)
等于 x 的情況,并了解它能替換為泰勒級(jí)數(shù)展開(kāi),以便犧牲特定精度。
跨平臺(tái)和架構(gòu)的浮點(diǎn)準(zhǔn)確性是 Burst 未來(lái)的目標(biāo)。
Unity 一直以組件的概念為中心,例如:我們可以添加 Rigidbody 組件到游戲?qū)ο笊希箤?duì)象能夠向下掉落。我們也可以添加 Light 組件到游戲?qū)ο笊希顾梢园l(fā)射光線。我們添加 AudioEmitter 組件,可以使游戲?qū)ο蟀l(fā)出聲音。
我們實(shí)現(xiàn)組件系統(tǒng)的方法并沒(méi)有很好地演變。我們過(guò)去使用面向?qū)ο蟮乃季S編寫(xiě)組件系統(tǒng)。組件和游戲?qū)ο蠖际恰按罅渴褂?C++ 代碼”的對(duì)象,創(chuàng)建或銷毀它們需要使用互斥鎖修改“id 到對(duì)象指針”的全局列表。
通過(guò)使用面向數(shù)據(jù)的思維方式,我們可以更好地處理這種情況。我們可以保留用戶眼中的優(yōu)良特性,即只需添加組件就可以實(shí)現(xiàn)功能,而同時(shí)通過(guò)新組件系統(tǒng)取得出色的性能和并行效果。
這個(gè)全新的組件系統(tǒng)就是實(shí)體組件系統(tǒng) ECS。簡(jiǎn)單來(lái)說(shuō),如今我們對(duì)游戲?qū)ο筮M(jìn)行的操作可用于處理新系統(tǒng)的實(shí)體,組件仍稱作組件。那么區(qū)別是什么?區(qū)別在于數(shù)據(jù)布局。
class Orbit : MonoBehaviour{ public Transform _objectToOrbitAround; void Update() { var currentPos = GetComponent<Transform>().position; var targetPos = _objectToOrbitAround.position; GetComponent<RigidBody>().velocity += SomehowSteerTowards(currentPos, targetPos) }}
這種模式會(huì)被反復(fù)使用:組件必須找到相同游戲?qū)ο笊系囊粋€(gè)或多個(gè)組件,然后給它讀取或?qū)懭霐?shù)值。
這種方法存在很多問(wèn)題:
Update()
方法被一個(gè)單獨(dú)的 Orbit 組件調(diào)用,下次調(diào)用 Update()
的會(huì)是完全不同的組件,它很可能造成代碼從緩存移出。
Update()
必須使用 GetComponent()
來(lái)找到 Rigidbody 組件。該組件也可以被緩存起來(lái),但必須保證 Rigidbody 組件不被銷毀。
我們要處理的其它組件位于內(nèi)存中完全不同的位置。
ECS 使用的數(shù)據(jù)布局會(huì)把這些情況看作一種非常常見(jiàn)的模式,并優(yōu)化內(nèi)存布局,使類似操作更加快捷。
離散的數(shù)據(jù)導(dǎo)致搜索效率十分低下,還有 Cache Miss 的問(wèn)題,這個(gè)問(wèn)題可以參考:ECS的泛泛之談
ECS 會(huì)在內(nèi)存中對(duì)帶有相同組件(Component)集的所有實(shí)體(Entity)進(jìn)行組合。ECS 把這類組件集稱為原型(Archetype)。
下圖的原型就是由 Position 組件、Velocity 組件、Rigidbody 組件和 Renderer 組件組成的。
如果一個(gè)實(shí)體只有三個(gè)組件(不同于前面提到的原型),那么那三個(gè)組件就組成了一個(gè)新的原型。
下面的圖來(lái)自 Unite LA 的一次演講的講義, 很遺憾那次演講沒(méi)有錄制下來(lái)。講義可以在這里找到。
ECS 以 16k 大小的塊(Chunk)來(lái)分配內(nèi)存,每個(gè)塊僅包含單個(gè)原型中所有實(shí)體的組件數(shù)據(jù)。
一個(gè)帖子中有人提供了更加形象的內(nèi)存布局圖,例如上半部分的原型由 Position 組件和 Rock 組件組成,其中整個(gè)原型占了一個(gè)塊(Chunk),兩個(gè)組件的數(shù)據(jù)分別存在兩個(gè)數(shù)組中,里面還帶著組件數(shù)據(jù)對(duì)應(yīng)的實(shí)體的信息。
每個(gè)原型都有一個(gè) Chunks 塊列表,用來(lái)保存原型的實(shí)體。我們會(huì)循環(huán)所有塊,并在每個(gè)塊中,對(duì)緊湊的內(nèi)存進(jìn)行線性循環(huán)處理,以讀取或?qū)懭虢M件數(shù)據(jù)。該線性循環(huán)會(huì)對(duì)每個(gè)實(shí)體運(yùn)行相同的代碼,同時(shí)為 Burst 創(chuàng)造向量化(Vectorization)處理的機(jī)會(huì)。
每個(gè)塊會(huì)被安排好內(nèi)存中的位置,以便于快速?gòu)膬?nèi)存得到想要的數(shù)據(jù),詳情可以參考下面的文章。
Unity2018 ECS框架Entities源碼解析(二)組件與Chunk的內(nèi)存布局 - 大鵬的專欄 - CSDN博客
實(shí)體是什么?實(shí)體只是一個(gè) 32 位的整數(shù) key (和一些額外的數(shù)據(jù)例如 index 和 version 實(shí)體版本,不過(guò)在這里不重要),所以除了實(shí)體的組件數(shù)據(jù)外,不必為實(shí)體保存或分配太多內(nèi)存。實(shí)體可以實(shí)現(xiàn)游戲?qū)ο蟮乃泄δ?,甚至更多功能,因?yàn)閷?shí)體非常輕量。
實(shí)體的性能消耗很低,所以我們可以把實(shí)體用在不適合游戲?qū)ο蟮那闆r,例如:為粒子系統(tǒng)內(nèi)的每個(gè)單獨(dú)粒子使用一個(gè)實(shí)體。
實(shí)體本身不是對(duì)象,也不是一個(gè)容器,它的作用是把其組件的數(shù)據(jù)關(guān)聯(lián)到一起。
我們不必使用用戶的 Update 方法搜索組件,然后在運(yùn)行時(shí)對(duì)每個(gè)實(shí)例進(jìn)行操作,使用 ECS 時(shí)我們只需靜態(tài)地聲明:我想對(duì)同時(shí)附帶 Velocity 組件和 Rigidbody 組件的所有實(shí)體進(jìn)行操作。為了找到所有實(shí)體,我們只需找到所有符合特定“組件搜索查詢”的原型即可,而這個(gè)過(guò)程就是由系統(tǒng)(System)來(lái)完成的。
很多情況下,這個(gè)過(guò)程會(huì)分成多個(gè) Job ,使處理ECS組件的代碼達(dá)到幾乎100%的核心利用率。ECS 會(huì)完成所有工作,我們只需要提供對(duì)每個(gè)實(shí)體運(yùn)行的代碼即可。我們也可以手動(dòng)處理塊迭代過(guò)程(IJobChunk)。
當(dāng)我們從實(shí)體添加或移除組件時(shí),ECS會(huì)切換原型。我們會(huì)把它從當(dāng)前塊移動(dòng)到新原型的塊,然后交換之前塊的最后實(shí)體來(lái)“填補(bǔ)空缺”。
在 ECS 中,我們還要靜態(tài)聲明要對(duì)組件數(shù)據(jù)進(jìn)行什么處理,是 ReadOnly 只讀還是 ReadWrite 讀寫(xiě)。通過(guò)確定僅對(duì) Position 組件進(jìn)行讀取,ECS 可以更高效地調(diào)度 Job ,其它需要讀取 Position 組件的 Job 不必進(jìn)行等待。
這種數(shù)據(jù)布局也處理了 Unity 長(zhǎng)期以來(lái)的困擾,即:加載時(shí)間和序列化的性能。為大型場(chǎng)景加載或流式處理 ECS 數(shù)據(jù)時(shí),主要的操作是從硬盤(pán)加載和使用原始字節(jié)。
對(duì) ECS 的常見(jiàn)觀點(diǎn)是:ECS 需要編寫(xiě)很多代碼。因此,實(shí)現(xiàn)想要的功能需要處理很多樣板代碼?,F(xiàn)在針對(duì)移除多數(shù)樣板代碼需求的大量改進(jìn)即將推出,這些改進(jìn)會(huì)使開(kāi)發(fā)者更簡(jiǎn)單地表達(dá)自己的目的。
我們暫時(shí)沒(méi)有實(shí)現(xiàn)太多這類改進(jìn),因?yàn)槲覀儸F(xiàn)在正專注于處理基礎(chǔ)性能,但我們知道:太多樣板代碼對(duì) ECS 游戲代碼沒(méi)有好處,我們不能讓編寫(xiě) ECS 代碼比編寫(xiě) MonoBehaviour 更麻煩。
Project Tiny 已經(jīng)實(shí)現(xiàn)了部分改進(jìn),例如:基于 lambda 函數(shù)的迭代 API。
以上是“Unity中DOTS要實(shí)現(xiàn)的特點(diǎn)有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前標(biāo)題:Unity中DOTS要實(shí)現(xiàn)的特點(diǎn)有哪些
當(dāng)前鏈接:http://www.rwnh.cn/article28/jieecp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、小程序開(kāi)發(fā)、網(wǎng)站收錄、、軟件開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)