個人ASP.NET程式效能最佳化心得(2):ASP.NET代碼最佳化

來源:互聯網
上載者:User

個人ASP.NET程式效能最佳化心得系列:

個人ASP.NET程式效能最佳化心得(1):資料庫篇

個人ASP.NET程式效能最佳化心得(1):資料庫篇(外一篇)

個人ASP.NET程式效能最佳化心得(2):ASP.NET代碼最佳化

個人ASP.NET程式效能最佳化心得(3):前端效能最佳化

------------------------------------------------------------------------------

對於影響ASP.NET程式效能的因素,重要性並非按資料庫、ASP.NET代碼、前端這樣來排序,不同的應用環境可能重要的影響因素都不一樣,除去外在硬體、網路等因素,使用者在地址欄裡輸入地址,到整個網頁完整顯示在使用者的瀏覽器中,這個時間等於所有因素之和。一般情況來講,在正常的情況下,處理這三種因素都需要不同的角色:DBA負責資料庫最佳化,程式員最佳化ASP.NET代碼、前端工程師最佳化前端效能,如果分工沒有這麼明細,就會出現分工出現交叉的情況;最壞的情況是,只有一個人,這個人既是DBA,又是程式員,還要書寫全部前端部分。——這可能是件壞事,你在一個摳門的老闆手裡,老闆把你當驢子來用;也會是一件好事,Web開發本身就是一件需要掌握眾多知識的工作,你會從中學習到更多的知識,這樣對理解網路程式會有更全面的認識(偶就是這麼過來的…………TAT)。

一、慎用伺服器控制項

ASP.NET中的伺服器控制項一部分是對html控制項的擴充,包括Button、Label、Literal、TextBox、DropDownList、CheckBox、RadioButton等,ASP.NET對這些控制項進行了封裝,同時對控制項進行了委託事件的綁定,這樣使得ASP.NET程式員就可以像VB、WinFornm那樣拖控制項的方式來去對介面進行布局和事件的處理。這類控制項產生的HTML控制項基本不會產生多餘的代碼,如果對Web標準不是很在意的話,影響不會很大。值得一提的是Label產生的是<span>標籤,CheckBox(List)、RadioButton(List)產生的標籤往往是這樣的:

<span class="checkBox"><input id="chkSel" type="checkbox" name="chkSel"  /><label for="chkSel">選擇</label></span>

這種代碼從Web標準上來看是要被前端工程師罵的,既無語義性又浪費代碼。

另一類伺服器控制項就是微軟引以為傲的大資料展示控制項,包括GridView、DataList、DetailsView、ListView、Repeater等,這類控制項除了Repeater控制項外,其他不推薦使用,這類傻瓜控制項會把程式員變得更加傻瓜,更重要的是會影響代碼效能,以GridView為例,在綁定DataSource後,所有的資料都會在伺服器的記憶體上一次載入,程式員最愛它的分頁功能——瞧,點幾下就可以了。但如果資料比較多,比如幾百頁、幾千頁,點一次等待的時間可以上一次廁所。Repeater控制項推薦使用,因為它不會產生任何代碼,僅是將資料來源的內容重複顯示出來。對於最最常用的分頁功能建議是預存程序+Repeater,這樣無論是從效能還是從HTML代碼整潔度來看都是合適的。

HTML算是Web開發人員最最基本的能力,如果不能手寫HTML很難勝任Web開發這項工作,使用Visual Studio拖控制項得來的代碼是非常混亂的,建議還是開啟源視圖一行一行地寫HTML,即使它是伺服器控制項。

二、ViewState的問題

ViewState本身是一個非常好的想法,微軟的創新能力在業界是公認的,起因是這樣的:使用者向伺服器提交資料,比如姓名、年齡、性別等,伺服器會對這些資料的合法性進行驗證,如果格式不正確或者輸入為空白這樣伺服器就會將一些錯誤資訊返回給使用者,但問題是使用者剛剛提交的表單內容都已經沒有了,如果表單中要填寫的內容比較多,使用者會發瘋的。這時ASP.NET就非常好心地把這些提交的內容都還儲存在這個網頁裡,即使資料提交未通過驗證,這些資料依然保持在它本來的位置上 ,這個做法非常的討好使用者和開發人員,對了,它往往和驗證控制項一起使用,看似非常人性化,但它卻是會產生大量臃腫代碼的罪魁禍首。

個人ASP.NET程式效能最佳化心得(2):asp.net代碼最佳化

這種亂七八糟的代碼是對已有的資料進行Base64加密後產生的結果,它會讓使用者的瀏覽器在下載你的網頁時感覺慢了一些。

我的觀點是,如果是互連網類產品(包含網站類)要全域把EnableViewState設為false,可以在Web.Config裡設定的。解決方案是使用Javascript進行驗證,現在的表單驗證庫使用起來是很方便的。

三、ADO.NET中的問題

 1、SqlDataReader和DataSet的選擇:

SqlDataReader是一種快速向前讀取資料的類,它對於從Sql Server資料來源檢索的資料採用只進資料流的方式,DataSet會將資料庫的內容以邏輯資料庫的方式存放在伺服器的記憶體中,如果資料量比較大,對伺服器的效能影響就比較大了。因此在實際項目中應該合理選擇。

2、ExecuteNonQuery和ExecuteScalar的選擇:

ExecuteScalar會返回執行結果後的第一行第一列資料,ExecuteNonQuery只會返回影響的行數,在一些情況下我們可能只需要知道是否已經執行成功了,也就是ExecuteNonQuery返回的行數是否大於0;有的時候我們還想知道返回結果的資料,比如在執行INSERT後我們需要使用SCOPE_IDENTITY()來得到返回的主鍵ID。可以根據實際需要選擇使用ExecuteNonQuery和ExecuteScalar。

四、合理使用緩衝

使用緩衝算是屬於重中之重,這個可以這麼來解釋:當有一百個人都需要到伺服器取一個資料,那麼程式每次都會到SQL Server資料庫中查詢取出資料,這樣將對效能造成很大的影響。可以將這個資料暫時緩衝到伺服器上,這樣第一個人查詢時會將這個資料存到伺服器的記憶體上,其餘的使用者在緩衝時間內都會直接從伺服器上取出這個資料,避免多次請求資料來源,這樣就會提升程式的效能。當然,如果是這個快取資料是動態變化的話,可以適當的設定緩衝時間,或者在更新資料時清除緩衝,這種情況比如在文章系統中會遇到。

我這裡提供了我個人使用的緩衝類:

using System;using System.Collections;using System.Web;using System.Web.Caching;namespace Cute.Utility{    /// <summary>    /// @ 緩衝處理    /// @ walkingp    /// @ http://www.cnblogs.com/walkingp    /// @ http://www.walkingp.com/    /// @ walkingp@126.com    /// @2011-05-01    /// </summary>    public class CacheHelper    {        private Cache webCache = HttpContext.Current.Cache;        private int defaultCacheTime = 60;        /// <summary>        /// 擷取某項        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public object Get(string key)        {            return this.webCache.Get(key);        }        /// <summary>        /// 判斷某項是否存在        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public bool Exists(string key)        {            return this.webCache.Get(key) != null;        }        /// <summary>        /// 增加某項到緩衝中        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <returns></returns>        public bool Add(string key, object value)        {            return this.Add(key, value, defaultCacheTime);        }        /// <summary>        /// 增加某項到緩衝中設定緩衝時間為minute分鐘        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <param name="minute">要緩衝的分鐘數</param>        /// <returns></returns>        public bool Add(string key, object value, int minute)        {            return this.Add(key, value, TimeSpan.FromMinutes(minute));        }        /// <summary>        /// 增加某項到緩衝中,並設定某項的緩衝時間        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <param name="span">要緩衝的時間片</param>        /// <returns></returns>        public bool Add(string key, object value, TimeSpan span)        {            this.webCache.Insert(key, value, null, DateTime.Now.Add(span), System.Web.Caching.Cache.NoSlidingExpiration);            return true;        }        /// <summary>        /// 增加某項到緩衝中,並設定要到期的緩衝時間        /// </summary>        /// <param name="key"></param>        /// <param name="value"></param>        /// <param name="expireTime">緩衝的到期時間</param>        /// <returns></returns>        public bool Add(string key, object value, DateTime expireTime)        {            this.webCache.Insert(key, value, null, expireTime, System.Web.Caching.Cache.NoSlidingExpiration);            return true;        }        /// <summary>        /// 把某項從緩衝中移除        /// </summary>        /// <param name="key"></param>        /// <returns></returns>        public bool Remove(string key)        {            return this.webCache.Remove(key) != null;        }        /// <summary>        /// 移除所有緩衝        /// </summary>        public void RemoveAll()        {            System.Web.Caching.Cache _cache = HttpRuntime.Cache;            IDictionaryEnumerator CacheEnum = _cache.GetEnumerator();            ArrayList al = new ArrayList();            while (CacheEnum.MoveNext()) {                al.Add(CacheEnum.Key);            }            foreach (string key in al) {                _cache.Remove(key);            }         }    }}

五、其他最佳化

1、避免拆箱裝箱:

我們知道C#中的實值型別和參考型別,C#基礎資料類型和Struct、Enum屬於實值型別,參考型別包括類、數組、介面、委託以及字串(String),不錯,字串也屬於參考型別;實值型別會以棧(Stack)的形式儲存在記憶體,參考型別會以堆(Heap)的形式儲存(這個概念也就是C語言的指標)。實值型別轉換為參考型別稱為裝箱,反之稱為拆箱。如下:

int i=0;Syste.Object obj=i;//裝箱int j=(int)obj;//拆箱

裝箱拆箱會影響程式效能,我們在程式中應該儘可能避免。因此程式這樣寫會提升那麼一點點的效能:

String info="My Age is" + 24.ToString();

2、使用StringBuilder

如果字串拼接過多,可能會影響程式效能,這樣因為每次++都會創新一個新的字串,也就是說會在記憶體中多開闢了一個空間給這個新的字串。使用StringBuilder可以減少這種消耗。建議在連接字串過多的情況下使用。

另外記得關於StringBuiler的問題曾經在部落格園爭吵過一次,如果有問題歡迎大家指出來。

3、避免不必要的ToLower()和ToUpper()

同上一樣,都會建立新的字串對象,如果沒有必要盡量減少使用,也可以使用Compare方法來比較字串。

4、避免不必要的異常捕獲

也許你對事物的考慮過於複雜,對於異常的捕獲也過于敏感,於是Try...Catch就用得多一點,那麼建議還是在該用的時候才用,不該用的時候不用。

5、使用預存程序

頻繁的SQL語句在Web伺服器傳遞到資料庫伺服器上來回傳輸會影響程式執行的效率,更為有效方式就是把語句比較複雜和需要比較頻繁使用的SQL語句封裝成預存程序進行調用。

總結

以上是我個人總結的ASP.NET代碼最佳化的一點方法和心得,這個層面的最佳化需要更多的是對C#語言、ADO.NET機制和ASP.NET運行機制掌握得更多和更加深入。最佳化無止境,歡迎完善和補充。

推薦書籍

《CLA Via C#》:這本書對c#進行了最深入的講解。

《ASP.NET本質論》:園子裡的朋友寫的一本書,上次跟dudu借看了(偶經常能看到dudu,羨慕不?),強烈推薦,誰說國內沒有好的IT圖書?

《C#圖解教程》:老外也玩標題黨,差點毀了一本好書,對於感覺自己對C#似懂非懂的同學一定要去買下這本書去認真讀一下,看的時候會有一種“so simple”的感覺。

-------------------------------------------------------

本文同時發表在我的個人首頁上:http://www.walkingp.com/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.