趁热打铁-一次.Net WebService的性能优化之旅
原文寫于:八月 9 2011 11:08 上午
?
公司里新上了一個項目,在做性能測試的時候發(fā)現(xiàn)一個奇怪的問題,跑同一個流程,在一個48核(HP580 G7 PC server)的服務(wù)器上耗時120秒,而在一個4核心的PC機上只要90秒,帶著這樣的疑問,公司請了微軟的相關(guān)工程師來解決此問題。
經(jīng)過一天的跟蹤調(diào)試和優(yōu)化,把耗時降至70幾秒,這其中過程包含幾個.net對象的優(yōu)化,確實效果很明顯。此文是階段性結(jié)論的一個筆記,也蠻具有指導(dǎo)意義。
?
一、DataView.ToTable()后的性能問題
工程師在跟蹤代碼的時候發(fā)現(xiàn)處理這個方法的時候很慢,占居了整個邏輯代碼的大部分時間。優(yōu)化這個方法后效果很明顯。
查了MSDN,官方并沒有給出DataView.ToTable()方法關(guān)于性能方面的提示,但是要MSDN看這個方法時,發(fā)現(xiàn)老外在06年的時候已經(jīng)在下面回了一段代碼,通過三個方式執(zhí)行這個方法,發(fā)現(xiàn)效率上差異很大。 (MSDN:DataView.ToTable())。
我復(fù)制代碼,創(chuàng)建了一個新的工程,確實可以重現(xiàn)問題。整個過程大概如下:
背景是有一個有500000條數(shù)據(jù)的DataTable,然后把這個DataTable中的數(shù)據(jù)賦給DataView,然后從這個DataView通過ToTable()方法,把數(shù)據(jù)轉(zhuǎn)給另外一個同架構(gòu)的DataTable。
第一種方式 創(chuàng)建目標DataTable對象,直接通過toTable()方法轉(zhuǎn)換。過程耗時:27.0504秒。
第二種方式 創(chuàng)建目標DaTaTable后,對其設(shè)置PrimaryKey。然后通過下面代碼向目標表添加數(shù)據(jù)。
? ? ? ? ? ? ? ???foreach (DataRow dr in ds.Tables[0].Rows)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? DataRow[] drrepetido = dsRes.Tables[0].Select("valor=" + dr["Valor"]);
? ? ? ? ? ? ? ? ? ? if (drrepetido.Length == 0)
? ? ? ? ? ? ? ? ? ? ? ? dsRes.Tables[0].ImportRow(dr);
? ? ? ? ? ? ? ? }
過程耗時:11.7624秒。
?
第三種方式 不根據(jù)原架構(gòu)創(chuàng)建目標DataTable,全新實例化DataTable對象,然后向其添加對應(yīng)列,然后創(chuàng)建哈希表,循環(huán)寫入目標表,代碼如下:
? ? ? ? ? ? ? ??DataTable dt = new DataTable();
? ? ? ? ? ? ? ? dt.Columns.Add("valor", ds.Tables[0].Columns["valor"].DataType);
? ? ? ? ? ? ? ? Hashtable ht = new Hashtable();
? ? ? ? ? ? ? ? foreach (DataRow dr in ds.Tables[0].Rows)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if (!ht.ContainsKey(dr[0]))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ht.Add(dr[0], null);
? ? ? ? ? ? ? ? ? ? ? ? DataRow newRow = dt.NewRow();
? ? ? ? ? ? ? ? ? ? ? ? newRow[0] = dr[0];
? ? ? ? ? ? ? ? ? ? ? ? dt.Rows.Add(newRow);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
過程耗時:0.2184秒。
?
三種方式對比,發(fā)現(xiàn)非常恐怖。但是微軟好像還沒有給出原因。
?
二、StringBuilder()使用不檔帶來的性能問題
?
關(guān)于StringBuilder之前也看過很多文章,這次開發(fā)商程序中的問題和以前的類似,實例化時沒有設(shè)置一個比較推薦的長度值,導(dǎo)致在循環(huán)體內(nèi)不斷appand()后,StringBuilder對象不斷被GC處理。從而消耗了很多時間。
關(guān)于StringBuilder()對象,還是再多加幾句吧。其默認維護的Capacity值是16。
因為StringBuilder對象的創(chuàng)建代價較大,在字符串連接目標較少的情況下,過度濫用StringBuilder會導(dǎo)致性能的浪費而非節(jié)約。只有大量的或者無法預(yù)知次數(shù)的字符串操作,才考慮以StringBuilder來實現(xiàn)。 ?String類型的“+”連接操作,實際上是重載操作符“+”調(diào)用String.Concat來操作,而編譯器則會優(yōu)化這種連接操作的處理,編譯器根據(jù)其傳入?yún)?shù)的個數(shù),一次性分配相應(yīng)的內(nèi)存,并依次拷入相應(yīng)的字符串。 StringBuilder在使用上,最好指定合適的容量值,否則由于默認容量不足而頻繁的進行內(nèi)存分配操作,是不妥的實現(xiàn)方法。 ?通常情況下,進行簡單字符串連接時,應(yīng)該優(yōu)先考慮使用String.Concat和String.Join等操作來完成字符串的連接,但是應(yīng)該留意String.Concat可能存在的裝箱操作。
?
三、拆裝箱帶來性能問題
如果用StringBuilder.toString().trim()來判斷StringBuilder是否有值的情況,可以用StringBuilder.Lenth()來代替。
?
?
其它等等
轉(zhuǎn)載于:https://www.cnblogs.com/redroot/archive/2013/01/24/2875843.html
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的趁热打铁-一次.Net WebService的性能优化之旅的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hibernate的Session介绍[
- 下一篇: LockBits in GDI+【转】h