您好,登錄后才能下訂單哦!
這篇文章主要介紹Unity中如何優(yōu)化字符串和文本,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
字符串和文本:
在Unity項(xiàng)目中,處理字符串和文本經(jīng)常會(huì)產(chǎn)生性能問題。在C#中,字符串是不變的。任何對(duì)字符串的操作都會(huì)重新分配新的字符串,這個(gè)代價(jià)是非常昂貴的。如果在多重循環(huán)中重復(fù)地執(zhí)行字符串連接操作,就會(huì)造成性能問題,特別是對(duì)長的字符串或者大的數(shù)據(jù)集操作的時(shí)候。
因此,把N個(gè)字符串連接起來就會(huì)分配N-1個(gè)中間的字符串,這樣連續(xù)的操作就會(huì)對(duì)堆內(nèi)存產(chǎn)生壓力。
當(dāng)我們需要在多重循環(huán)中或者每一幀對(duì)字符串進(jìn)行操作時(shí),記得使用StringBuilder來操作字符串。StringBuilder也還能被重用,以進(jìn)一步減少內(nèi)存的分配。
關(guān)于字符串的使用,詳細(xì)內(nèi)容也可以參考微軟發(fā)布的文檔:
Best Practices for Using Strings in .NET docs.microsoft.com
https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings
地域限制和順序比較:
與字符串相關(guān)代碼的一個(gè)核心問題就是無意中會(huì)使用默認(rèn)的、慢的字符串API。這些API的目的是為了一些商業(yè)化的應(yīng)用,能夠處理出現(xiàn)在文本中的有關(guān)不同文化和語法規(guī)則的字符。
比如,下面的代碼在一些使用美式英語的地區(qū)運(yùn)行時(shí),會(huì)返回true。在歐洲地區(qū)運(yùn)行時(shí),返回false。
提示:Unity腳本都是基于美式英語來運(yùn)行的。
對(duì)于大多數(shù)的項(xiàng)目,這個(gè)完全沒有必要。而且我們簡單對(duì)每個(gè)字符進(jìn)行比較,判斷兩個(gè)字符串是否相等,這速度大約會(huì)比使用上面的方式快10倍。當(dāng)然,我們也可以調(diào)用String.Equals方法,然后設(shè)置比較類型StringComparison.Ordinal來實(shí)現(xiàn):
低效率的內(nèi)置字符串API:
除了上面講的順序比較外,也有一些C#的字符串的API效率比較低。比如:String.Format,String.StartsWith和String.EndsWith。以下是Unity給出的一些測試數(shù)據(jù):
可見,如果是我們自己實(shí)現(xiàn)String.StartsWith和String.EndsWith,執(zhí)行效率會(huì)高的多。實(shí)現(xiàn)方法也可以參考下圖:
正則表達(dá)式:
在字符串匹配和操作字符串方面,正則表達(dá)式是非常消耗性能的。而且,C#類庫也實(shí)現(xiàn)了正則表達(dá)式。所以,即使是調(diào)用IsMatch這樣簡單的函數(shù),都會(huì)臨時(shí)分配很多的內(nèi)存。我們在開發(fā)中,出了初始化會(huì)臨時(shí)分配內(nèi)存外,應(yīng)該不允許在其他地方臨時(shí)分配較多內(nèi)存。
如果一定要用正則表達(dá)式的話,注意不要使用靜態(tài)的Regex.Match和Regex.Replace方法。這兩個(gè)方法會(huì)動(dòng)態(tài)的編譯正則表達(dá)式,但不會(huì)緩存生成的對(duì)象。
下面是使用正則表達(dá)式的一個(gè)例子:
每一次以上的代碼被執(zhí)行,它都會(huì)生成5kb的內(nèi)存垃圾。為了減少垃圾的生成,我們需要對(duì)以上代碼進(jìn)行重構(gòu):
在這個(gè)例子中,每一次調(diào)用myRegExp.Match只會(huì)產(chǎn)生320b的內(nèi)存垃圾。對(duì)于簡單的字符串匹配而言,它對(duì)內(nèi)存的消耗依舊有點(diǎn)多,但與之前的例子相比,這已經(jīng)是很大的改進(jìn)了。
因此,如果正則表達(dá)式是不變的字符串常量,那么把它們當(dāng)作第一個(gè)參數(shù)傳遞給Regex的構(gòu)造器來預(yù)編譯它們會(huì)更加有效。這些Regex對(duì)象也是可以被重用的。
XML, JSON和其他的長篇文本解析:
在loading時(shí),解析文本通常是一項(xiàng)耗時(shí)的操作。有些情況下,解析文本所花的時(shí)間會(huì)超過loading和實(shí)例化Assets的時(shí)間。
這原因取決于我們用的文本解析器。C#內(nèi)置的XML解析器是非常靈活的,但是,它不能對(duì)一些特殊的數(shù)據(jù)布局進(jìn)行優(yōu)化。
許多第三方解析器都是基于反射構(gòu)建的。雖然在開發(fā)中使用反射是一個(gè)不錯(cuò)的選擇(因?yàn)樗芎芎玫倪m應(yīng)數(shù)據(jù)布局的變化),但用反射是非常慢的。
Unity已經(jīng)引入了一個(gè)帶有內(nèi)置JSONUtility API(可參考:https://docs.unity3d.com/ScriptReference/JsonUtility.html)的局部解決方案,它為Unity的序列化系統(tǒng)提供了一個(gè)接口,用來處理JSON數(shù)據(jù)。在許多方面它是優(yōu)于C#的JSON解析器。但是它也有不足之處,在不添加額外代碼的情況下,它不能序列化許多復(fù)雜的數(shù)據(jù)類型,比如字典(在Unity的序列化過程中,請參閱ISerializationCallbackReceiver接口,以方便轉(zhuǎn)換一些復(fù)雜的數(shù)據(jù)類型)
如果在文本解析中遇到性能問題,可以考慮以下的解決方案:
1.在Build時(shí)進(jìn)行解析
當(dāng)我們需要解析文本時(shí),最好避免在游戲中進(jìn)行這一步的操作。我們可以在Build的時(shí)候把文本解析成二進(jìn)制文件。以加快讀取時(shí)的速度。
2.數(shù)據(jù)分割和延遲加載
第二種情況情況是我們需要把能解析成小塊的數(shù)據(jù)分割開來。一旦分割,數(shù)據(jù)解析就可以在不同時(shí)間進(jìn)行。在理想的情況下,我們確定哪部分?jǐn)?shù)據(jù)是會(huì)用到的,然后只加載用到的那部分?jǐn)?shù)據(jù)。
3.線程
對(duì)于那些不需要用Unity API來操作的數(shù)據(jù),可以在另外的線程中來解析它們。這可以提高多核CPU的利用率,是相當(dāng)有用的。當(dāng)然,我們在寫代碼時(shí)需要注意避免死鎖。
以上是“Unity中如何優(yōu)化字符串和文本”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。