從ECS架構說開來,聊一聊特定領域內理論的深度與廣度

前進!前進!不擇手段的前進!

1、ECS是什麼

image.png

Entity(實體) Component(組件) System(系統)
是一種基於數據的設計(DOD Data-Oriented Design)html

dodbook
ECS的泛泛之談
深刻淺出Unity ECS
ECS 真的是「將來主流」的架構嗎?
面向對象編程的弊端是什麼?
面向數據編程git

  1. 實體:持有全局惟一標記
  2. 組件:僅持有數據 純數據
  3. 系統:僅持有邏輯 純函數
for (s in systems) {
    s.doSomething(data);  // data爲對應系統須要使用的數據
}

Q:什麼是邏輯幀?
A:任何一個持續運行的程序,內部都有一個死循環。每執行一次循環,稱爲一個邏輯幀github

2、幾種設計流派的理解

  • OOD(Object-Oriented Design)編程

    • 總結共同數據與邏輯,抽象到基類中
  • COD(Compoment-Oriented Design) 緩存

    • 打包數據與邏輯,抽象成一個個的組件對象
    • 基於組件
    • 僅抽象出共有邏輯,規範行爲
  • DOD(Data-Oriented Design)服務器

    • 以COD爲基礎,再把數據、邏輯分離

3、流派總結

實際上基於組件與基於接口本質相同,都是爲了解決傳統基於對象致使基類太重的問題。
基於組件、基於接口也獲得了普遍的應用。多線程

基於對象設計:基於現實的抽象。對象持有本身的全部數據、行爲。架構

  • 優勢:容易理解。基於接口的設計方式已經足夠好。行爲的統1、類之間的解耦都很好。
  • 缺點:性能上限低。面向對象編程的弊端是什麼?

基於數據設計:行爲是行爲,數據是數據。行爲只處理數據。行爲自己不屬於某個具體的對象。 函數

  • 優勢:能夠作到極致的性能 面向數據編程
  • 缺點:難理解,高性能的工程實現很難

作ECS是爲了優化性能,由於接口編程已經足夠解耦了。

4、基於數據的設計,爲何能夠作到高性能?

先看下傳統寫法爲何低效性能

for (p in players) {
    if (condition) {
        p.doSth();
    }
}
  • 數據內存上離散,緩存不友好
  • 分支預測不友好
  • 虛函數調用開銷大

5、CPU緩存友好

CPU讀取內存比較慢,因此設計了一套緩存
一次讀取一個cache line長度的數據

緩存三要素

  • 在相對較慢的交互之間插入一個高速的緩存層
  • 緩存層須要有數據卸載機制
  • 預測式加載數據

廣度:

  • 服務器的緩存技術
  • 客戶端的緩存技術
  • 還有沒有其餘的?

深度:

6、分支預測

處理器猜想進入哪一個分支,而且基於預測結果來取指、譯碼。
若是猜想正確,就能節省時間。
若是猜想錯誤,刷新流水線,在新的地址處取指、譯碼。

廣度:

深度

7、虛函數調用開銷

對每個虛函數的調用都須要額外的指針尋址
虛函數一般不能被inline,當虛函數都是小函數時會有比較大的性能損失
每一個對象都須要有一個額外的指針指向虛表

C++的靜態分發(CRTP)和動態分發(虛函數多態)的比較

8、以上三個問題,須要怎麼解決?

  1. 緩存友好

    • 語言須要支持POD類型
    • 須要三個基本池

      • 內存池 – 減小系統調用
      • 線程池 – 真正的並行
      • 對象池 – 數據連續存儲的保證
  2. 分支預測

    • 任何語言均可以
  3. 虛函數調用開銷

    • 須要支持簡單函數的定義

9、再總結:那做爲腳本工程師,應該集中精力關心哪裏?

設計 >= 虛擬機版本 >> 語法

相關文章
相關標籤/搜索