面向数据编程
面向?qū)ο缶幊虒訉映橄笤斐捎纺[,導(dǎo)致運(yùn)行效率降低,而這是性能要求高的游戲編程領(lǐng)域不想看到的。
面向過程:建立解決問題所需的各個(gè)步驟(函數(shù))。
面向?qū)ο?#xff1a;建立解決問題所需的各個(gè)模型(類)。
面向數(shù)據(jù):考慮數(shù)據(jù)的存取及布局(數(shù)據(jù))。
值得一說的是,面向過程和面向?qū)ο?/span>都是解決問題的一種方法,而面向數(shù)據(jù)只是一種優(yōu)化的設(shè)計(jì)思想,而非解決問題的方法。
冷數(shù)據(jù)/熱數(shù)據(jù)分割
我們希望CPU緩存存儲(chǔ)的是經(jīng)常使用的數(shù)據(jù),而不是那些少用的數(shù)據(jù)。這就引入了冷數(shù)據(jù)/熱數(shù)據(jù)分割的概念了。
熱數(shù)據(jù):經(jīng)常要操作使用的數(shù)據(jù),我們一般可以直接作為可直接訪問的成員變量。
冷數(shù)據(jù):比較少用的數(shù)據(jù),我們一般以引用/指針來間接訪問(即存儲(chǔ)的是指針或者引用)。
一個(gè)例子:對(duì)于人類來說,生命值位置速度都是經(jīng)常需要操作的變量,是熱數(shù)據(jù)。
而掉落物對(duì)象只有人類死亡的時(shí)候才需要用到,所以是冷數(shù)據(jù);
頻繁調(diào)用的函數(shù)盡可能不要做成虛函數(shù)
C++的虛函數(shù)機(jī)制,簡單來說是兩次地址跳轉(zhuǎn)的函數(shù)調(diào)用,這對(duì)CPU緩存十分不友好,往往命中失敗。實(shí)際上虛函數(shù)可以優(yōu)雅解決很多面向?qū)ο蟮膯栴},然而在游戲程序如果有很多虛函數(shù)都要頻繁調(diào)用(例如每幀調(diào)用),很容易引發(fā)性能問題。
解決方法是,把這些頻繁調(diào)用的虛函數(shù)盡可能去除virtual特性(即做成普通成員函數(shù)),并避免調(diào)用基類對(duì)象的成員函數(shù),代價(jià)是這樣一改得改很多與之牽連代碼。所以最好一開始設(shè)計(jì)程序時(shí),需要先想好哪些最好不要寫成virtual函數(shù)。
重新認(rèn)識(shí)C++ STL容器
STL容器,特別是set,map,有著很多O(logN)的操作速度,但并不意味著是最佳選擇,因?yàn)檫@種復(fù)雜度表示往往隱藏了常數(shù)很大的事實(shí)。
例如說,集合的主流實(shí)現(xiàn)是基于紅黑樹,基于節(jié)點(diǎn)存儲(chǔ)的,而每次插入/刪除節(jié)點(diǎn)都意味著調(diào)用一次系統(tǒng)分配內(nèi)存/釋放內(nèi)存函數(shù)。這相比vector等矢量容器所有操作僅一次系統(tǒng)分配內(nèi)存(理想情況來說),實(shí)際上就慢了不少。
此外,矢量容器對(duì)CPU緩存更加友好,遍歷該種容器容易命中緩存,而節(jié)點(diǎn)式容器則相對(duì)容易命中失敗。
綜合上述,如果要選擇一個(gè)最適合的容器,那么不要過度信賴時(shí)間復(fù)雜度,除非你十分徹底的了解STL容器,或?qū)Ω魅萜鬟M(jìn)行多次效率測(cè)試。
總結(jié)
對(duì)面向?qū)ο蠛兔嫦驍?shù)據(jù)的看法:應(yīng)該兼有。
因?yàn)橛螒虺绦蚴且粋€(gè)既需要高性能又復(fù)雜的工程。使用面向?qū)ο蟮挠螒虺绦蛐率?#xff0c;常常就有一個(gè)問題:過度設(shè)計(jì)/過度抽象,什么都想用設(shè)計(jì)模式封裝一下抽象一下。這就很容易導(dǎo)致一些過度設(shè)計(jì)/過度抽象導(dǎo)致游戲性能太差。
面向數(shù)據(jù)思想,盡量減少虛函數(shù)的使用,多利用數(shù)據(jù)組合成對(duì)象,而不是重寫各種基類虛函數(shù)。對(duì)于一些數(shù)據(jù)結(jié)構(gòu)的考量,也盡量偏多使用連續(xù)存儲(chǔ)的結(jié)構(gòu)(例如數(shù)組)。
總結(jié)
- 上一篇: 通信标准3之PUSCH频率域资源分配
- 下一篇: android11.0 12.0Laun