Unity中資源依賴關系獲取優(yōu)化

今天和大家分享一個優(yōu)化經(jīng)驗只磷,主要關于獲取一個資源的依賴資源列表即對AssetDatabase.GetDependencies這個接口的調(diào)用效率優(yōu)化泌绣。通過一步步優(yōu)化最后在對工程中所有資源獲取依賴資源的執(zhí)行上提升了近100倍的效率。

在對AssetBundle進行打包時候元媚,需要獲取資源的依賴關系苗沧,并生成最后所有資源的BundleName。這里主要的瓶頸就是對資源的依賴關系數(shù)據(jù)獲取上鞠绰。在工程實踐中發(fā)現(xiàn)整個構建環(huán)節(jié)20分鐘飒焦,16分鐘是BuildAssetBundles開銷,3分鐘是GetDependencies開銷翁巍。在增量構建中休雌,BuildAssetBundles可降為1-3分鐘,而GetDependencies則仍需要3分鐘開銷杈曲。當然對于資源數(shù)量較小的工程,這個優(yōu)化就是一個可有可無的選項對構建速度影響不大恰响。

還有一個常見的應用場景就是快速查找資源資源的依賴數(shù)據(jù)以及被依賴數(shù)據(jù)涌献,也可以通過這次的優(yōu)化帶來體驗上提升。

首先從分析AssetDatabase.GetDependencies這個接口的行為開始枢劝,簡單的編寫一個測試函數(shù):

public static void Test()
{
    long timeStamp = Stopwatch.GetTimestamp();
    string[] dir = Directory.GetFiles("Assets/", "*.*", SearchOption.AllDirectories);
    for (int i = 0; i < dir.Length; ++i)
    {
        if (dir[i].EndsWith(".meta", System.StringComparison.OrdinalIgnoreCase))
        {
            continue;
        }
        AssetDatabase.GetDependencies(dir[i], true);
    }
    UnityEngine.Debug.LogFormat(
        "GetDependencies cost {0} ms.", 
        (Stopwatch.GetTimestamp() - timeStamp) * 1000 / Stopwatch.Frequency
    );
}

通過執(zhí)行這個函數(shù)可以了解這個函數(shù)的開銷卜壕,以及獲得數(shù)據(jù)為之后的優(yōu)化做對比。

第一次執(zhí)行的時候較慢鹤盒,有較高的硬盤讀寫轮蜕,總共花費6.3mins。

第二次執(zhí)行的時候快了近一倍跃洛,基本無硬盤讀寫,總共花費3.2mins葱蝗。

這里硬盤是使用SSD细燎,如果使用機械鍵盤則這里性能堪憂,第二次基本所有內(nèi)容都進了內(nèi)存悼凑,操作系統(tǒng)做了緩存,所以快了很多户辫。所以換更好的硬盤可以提高這里的效率,不過現(xiàn)在的執(zhí)行時間還是太長了墓塌。

如果對所有的資源進行掃描通過GUID去查詢并獲取依賴關系奥额,那應該不止這么點時間。這里猜測Unity做過一些數(shù)據(jù)預處理與緩存來優(yōu)化這個接口效率韩肝。

這時候第一個優(yōu)化思路是Cache棒拂,通過緩存每次結果下次查詢時可以立即返回結果。不過由于資源會修改帚屉,依賴文件會發(fā)生變化,所以緩存可能會出錯喻旷。如果不能判斷當前緩存是否有效牢屋,則只能在確保資源部修改的情況下使用緩存數(shù)據(jù)。

這里使用AssetDatabase.GetAssetDependencyHash來驗證緩存是否有效锋谐,這個接口返回Asset的一個Hash值(包括文件名以及meta文件)截酷,如果Hash值不變,我們可以認為這個Asset直接依賴的資源文件不變迂苛,由于直接依賴是通過Asset文件內(nèi)部的GUID索引的三幻,所以Hash不變即表示GUID不變,即依賴關系不變念搬。這里緩存Hash值以及這個Asset的直接依賴摆出。通過所有的直接依賴夷野,可以快速的計算出這個Asset的全部依賴荣倾。

AssetDatabase.GetAssetDependencyHash接口非常高效,這里簡單討論下妒貌。

這部分數(shù)據(jù)在Import Asset的時候計算并緩存铸豁,所以可以高效獲取。每個Asset都有自己的AssetDependencyHash在刺,Reimport的時候重新計算头镊。這里判斷文件是否修改的依據(jù)是文件最后修改時間是否發(fā)生變化。獲取目錄下所有文件信息由于有操作系統(tǒng)文件系統(tǒng)做了索引是非常高效的颖杏。

由于Refresh是一個必要項坛芽,這項開銷已經(jīng)花費出去了,所以這里可以直接享受接口的高效率咙轩。

最后只要把每次的數(shù)據(jù)保存在本地,下次使用的時候先從本地加載丐膝,即可使這部分邏輯時間優(yōu)化到2800ms左右胧弛,優(yōu)化了近100倍,這里的執(zhí)行效率已經(jīng)非常優(yōu)異了损晤,主要開銷在GetFiles上红竭。

上面只討論了有緩存數(shù)據(jù)情況下的優(yōu)化情況喘落,但實際緩存數(shù)據(jù)的加載和保存時間卻被忽略了最冰。實際結果是這部分的數(shù)據(jù)量較大,加載和保存開銷也比較大赌朋,如果使用Json來存儲的話篇裁,這里大概要花費1.5mins來讀寫這數(shù)據(jù)。

這里討論下對這個數(shù)據(jù)存儲效率的優(yōu)化达布,首先來看看數(shù)據(jù)結構:

public class DepenData
{
    public string assetPath;
    public Hash128 assetDependencyHash;
    public string[] dependsPath;
}
// save data
Dictionary<string, DependData> m_data;

基本都是字符串數(shù)據(jù)黍聂,存儲出來的文件都有300M左右(大概,具體忘了)产还,把Json存儲改為二進制以后雕沉,文件大小縮減為75M左右,加載時間從1.5mins變成了18.3S坡椒。較大的改進,不過還可以在改進我想汗唱。

這里依賴數(shù)據(jù)是遞歸即 A依賴B丈攒,B依賴C,在A的DependData里面就會有ABC际插,而B的依賴數(shù)據(jù)里面有BC显设。這里可以發(fā)現(xiàn)BC出現(xiàn)了兩次,如果能把消除重復字符串瑟枫,則可以近一步較少文件大小,提高讀寫速度慷妙。

修改后的結構如下:

public class DepenData
{
    public int assetPathIndex;
    public Hash128 assetDependencyHash;
    public int[] dependsPathIndex;
    public string[] dependsPath; // 用于返回查詢結果,不保存
}
// save data
Dictionary<string, DependData> m_data;
List<string> m_strList;
// temp data
Dictionary<string, int> m_strIndex;

改進后文件大小變?yōu)?8M虑啤,加載時間從18.3S優(yōu)化到3.3S猿挚。6倍的改進,挺棒的,這時候又在思考是否有改進的余地办绝。

第一個改進姚淆,把FileStream改為MemoryStream,數(shù)據(jù)則通過File.ReadAllBytes()讀取腌逢。這個改造可以把3.3S改進為3S搏讶,主要是由于FileStream API調(diào)用的效率并不高,這里是通過減少調(diào)用頻率來改進效率媒惕。對于FileStream每次ReadByte(2)和每次ReadByte(1024),可能有接近100倍的性能差異穿挨。

第二個改進肴盏,分析發(fā)現(xiàn)3S里面BinaryReader占用了2.7S,剩下數(shù)據(jù)結構組織贞绵,填充Dictionary占用了0.3S幌墓。C#的BinaryReader實現(xiàn)并不高效冀泻,可以通過更高效的序列化數(shù)據(jù)方式來優(yōu)化蜡饵。這里嘗試使用了FlatBuffers來替換BinaryReader溯祸,保存的開銷從880ms增長到1200ms,讀取的時間從3000ms優(yōu)化到1200ms焦辅。又是一次大幅度的優(yōu)化筷登,雖然現(xiàn)在收益時間已經(jīng)無關緊要了,不過實踐和驗證想法也是不錯的收獲前方。這里開啟FlatBuffers Unsafe模式應該會有更高的收益惠险,接近C++的性能,如果直接用C++寫性能果然會好很多吧班巩。

Unity所有路徑都是Assets開頭,大量路徑字符串里面前綴包含重復數(shù)據(jù)逊桦,數(shù)據(jù)結構還可以再改進......

把二進制文件壓縮后從28M變成5M遥缕,確實很多冗余數(shù)據(jù),不過再改進可能付出太多時間而受益太低夕凝。這次的優(yōu)化就到此為止了嘛户秤。

這里上最后一個優(yōu)化思路異步化

異步加載在游戲中是很常見的做法转砖,所以這里其實再實現(xiàn)兩個異步化接口即可把這部分時間優(yōu)化為0,由于還有其他很多任務可以并行執(zhí)行府蔗,所以這部分時間在調(diào)整到適當?shù)臅r機后可以忽略不計姓赤。

由于Unity的接口不能在多線程調(diào)用,所以一開始就不會往這個方面思考不铆,后面問題轉(zhuǎn)化后異步是一個非常優(yōu)異的做法,F(xiàn)latBuffers的改造非常繁瑣誓斥,浪費了我大量測試時間。最后我把代碼回滾到二進制版本劳坑,F(xiàn)latBuffers在運行時確實能帶來巨大的效率提升毕谴,不過這里可能并不需要上這個利器了。

一泡垃、二的優(yōu)化是基于專注性思維的思考結果析珊,而三則是發(fā)散性思維的思考結果。專注性思維容易陷入思維定式蔑穴,這時候可以起來喝杯茶,出去散散步惧浴。

[完 Carber 2018-08-12]

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末存和,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子衷旅,更是在濱河造成了極大的恐慌捐腿,老刑警劉巖柿顶,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茄袖,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘁锯,警方通過查閱死者的電腦和手機宪祥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來家乘,“玉大人蝗羊,你說我怎么就攤上這事∪示猓” “怎么了耀找?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長业崖。 經(jīng)常有香客問我野芒,道長蓄愁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任狞悲,我火速辦了婚禮撮抓,結果婚禮上,老公的妹妹穿的比我還像新娘效诅。我一直安慰自己胀滚,他們只是感情好,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布乱投。 她就那樣靜靜地躺著咽笼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪戚炫。 梳的紋絲不亂的頭發(fā)上剑刑,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機與錄音双肤,去河邊找鬼施掏。 笑死,一個胖子當著我的面吹牛茅糜,可吹牛的內(nèi)容都是我干的七芭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼蔑赘,長吁一口氣:“原來是場噩夢啊……” “哼狸驳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缩赛,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤耙箍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酥馍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辩昆,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年旨袒,在試婚紗的時候發(fā)現(xiàn)自己被綠了汁针。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡峦失,死狀恐怖扇丛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尉辑,我是刑警寧澤帆精,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響卓练,放射性物質(zhì)發(fā)生泄漏隘蝎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一襟企、第九天 我趴在偏房一處隱蔽的房頂上張望嘱么。 院中可真熱鬧,春花似錦顽悼、人聲如沸曼振。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冰评。三九已至,卻和暖如春木羹,著一層夾襖步出監(jiān)牢的瞬間甲雅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工坑填, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抛人,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓脐瑰,卻偏偏與公主長得像妖枚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子苍在,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

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