亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C#中那些[舉手之勞]的性能優化

2019-11-14 16:46:54
字體:
來源:轉載
供稿:網友

隔了很久沒寫東西了,主要是最近比較忙,更主要的是最近比較懶......

其實這篇很早就想寫了

工作和生活中經??梢钥吹揭恍┏绦蛟?寫代碼的時候只關注代碼的邏輯性,而不考慮運行效率

其實這對大多數程序猿來說都是沒有問題的

不過作為一只有理想的CodeMonkey,我還是希望給大家分享一些性能優化心得

 

曾經在網上聽過這樣一句話

程序的可讀性和性能是成反比的

我非常贊同這句話,所以對于那些極度影響閱讀的性能優化我就不在這里贅述了

今天主要說的就是一些舉手之勞即可完成的性能優化

 

 減少重復代碼

這是最基本的優化方案,盡可能減少那些重復做的事,讓他們只做一次

比較常見是這種代碼,同樣的Math.Cos(angle) 和Math.Sin(angle)都做了2次

PRivate Point RotatePt(double angle, Point pt){     Point pRet = new Point();     angle = -angle;     pRet.X = (int)((double)pt.X * Math.Cos(angle) - (double)pt.Y * Math.Sin(angle));     pRet.Y = (int)((double)pt.X * Math.Sin(angle) + (double)pt.Y * Math.Cos(angle));     return pRet;}

優化后

private Point RotatePt3(double angle, Point pt){    Point pRet = new Point();    angle = -angle;    double SIN_ANGLE = Math.Sin(angle);    double COS_ANGLE = Math.Cos(angle);    pRet.X =(int)(pt.X * COS_ANGLE - pt.Y * SIN_ANGLE);    pRet.Y = (int)(pt.X * SIN_ANGLE + pt.Y * COS_ANGLE);    return pRet;}

還有另一種 ,在方法中實例化一個對象, 但是這個對象其實是可以復用的

public static string ConvertQuot(string html){    Regex regex = new Regex("&(quot|#34);", RegexOptions.IgnoreCase);    return regex.Replace(html, "/"");}

優化后

readonly static Regex ReplaceQuot = new Regex("&(quot|#34);", RegexOptions.IgnoreCase | RegexOptions.Compiled);public static string ConvertQuot(string html){    return ReplaceQuot.Replace(html, "/"");}

還有一種是不必要的初始化,比如調用out參數之前,是不需要初始化的

public bool Check(int userid){    var user = new User();    if(GetUser(userid,out user))    {        return user.Level > 1;    }    return false;}

這里的new User()就是不必要的操作,

優化后

public bool Check(int userid){    User user;    if(GetUser(userid,out user))    {        return user.Level > 1;    }    return false;}

不要迷信正則表達式

正好在第一個栗子里說到了正在表達式(Regex)對象就順便一起說了

很多人以為正則表達式很快,非???超級的快

雖然正則表達式是挺快的,不過千萬不要迷信他,不信你看下面的栗子

//方法1public static string ConvertQuot1(string html){    return html.Replace(""", "/"").Replace(""", "/"");}readonly static Regex ReplaceQuot = new Regex("&(quot|#34);", RegexOptions.IgnoreCase | RegexOptions.Compiled);//方法2public static string ConvertQuot2(string html){    return ReplaceQuot.Replace(html, "/"");}

有多少人認為正則表達式比較快的,舉個手??

結果為10w次循環的時間 ,即使是10個Replace連用,也比Regex好,所以不要迷信他

//方法1public static string ConvertQuot1(string html){    return html.Replace("0", "").Replace("1", "").Replace("2", "").Replace("3", "").Replace("4", "").Replace("5", "").Replace("6", "").Replace("7", "").Replace("8", "").Replace("9", "");}readonly static Regex ReplaceQuot = new Regex("[1234567890]", RegexOptions.IgnoreCase | RegexOptions.Compiled);//方法2public static string ConvertQuot2(string html){    return ReplaceQuot.Replace(html, "");}

ConvertQuot1:3518
ConvertQuot2:12479

最后給你們看一個真實的,杯具的栗子

Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"([/r/n])[/s]+", "", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"-->", "", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(quot|#34);", "/"", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(iexcl|#161);", "/xa1", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(cent|#162);", "/xa2", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(pound|#163);", "/xa3", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&(copy|#169);", "/xa9", RegexOptions.IgnoreCase);Htmlstring = Regex.Replace(Htmlstring, @"&#(/d+);", "", RegexOptions.IgnoreCase);
View Code

合理使用正則表達式

上面說了正則表達式的效率不高,并不是說就不要用他了,至少正則表達式的作用不僅僅如此而已

如果一定要用正則表達式的話也需要注意,能靜態全局公用的盡量全局公用

readonly static Regex regex = new Regex("[1234567890]", RegexOptions.Compiled);

注意他的第二個參數RegexOptions.Compiled 注釋是  指定將正則表達式編譯為程序集。這會產生更快的執行速度,但會增加啟動時間。

通俗的說就是加了這個枚舉,會使得初始化Regex對象變慢,但是執行字符串查找的時候更快, 不使用的話,初始化很多,查詢比較慢

之前測過相差蠻大的 ,代碼就不比較了,有興趣的可以自己試試相差多少

另外還有一些枚舉項,不確定是否對性能有影響,不過還是按規則使用會比較好

  • RegexOptions.IgnoreCase    // 指定不區分大小寫的匹配,  如果表達式中沒有字母,則不需要設定
  • RegexOptions.Multiline         // 多行模式。更改 ^ 和 $ 的含義....  如果表達式中沒有^和$,則不需要設定
  • RegexOptions.Singleline       // 指定單行模式。更改點 (.) 的含義....  如果表達式中沒有.,則不需要設定

讓編譯器預處理常量的計算

編譯器在編譯程序段的時候 如果發現有一些運算是常量對常量的,那么他會在編譯期間就計算完成,這樣可以使程序在執行時不用重復計算了

比如

不過編譯器有的時候也不是那么聰明的

這個時候就需要我們幫助一下了

給他加一個括號,讓他知道應該先計算常量,這樣就可以在編譯期間進行運算了

字符串比較

這個可能很多人知道了,但還是提一下

string s = "";1) if(s == ""){}2) if(s == string.Empty){}3) if (string.IsNullOrEmpty(s)) { }4) if(s != null && s.Length ==0) {} 5) if((s+"").Length == 0){}  

 

1,2最慢 3較快 4,5最快

1,2幾乎沒區別 4,5幾乎沒區別

不過這個只適用于比較null和空字符串,如果是連續的空白就是string.IsNullOrWhiteSpace最快了,不過這個方法2.0里面沒有

所以2.0可以這樣 (s+"").trim() == 0 

這里的關鍵就是 s + ""  這個操作可以把null轉換為""

注意第二個參數只能是""或string.Empty 這樣的累加幾乎是不消耗時間的,如果第二個參數是" "(一個空格)這個時間就遠遠不止了

字符串拼接

字符串累加,這個道理和Regex一樣,不要盲目崇拜StringBuilder

在大量(或不確定的)string拼接的時候,StringBuilder確實可以起到提速的作用

而少數幾個固定的string累加的時候就不需要StringBuilder 了,畢竟StringBuilder 的初始化也是需要時間的

感謝#5樓 2014-03-24 16:45 殘蛹 博友提供的說明

ps: 這段我確實記得我是寫過的來著,不知道怎么的,發出來的時候就不見了.....

此外還有一個string.Concat方法,該方法可以小幅度的優化程序的速度,幅度很小

他和string.Join的區別在于沒有間隔符號(我之前常用string.Join("",a,b,c,d),不要告訴我只有我一個人這么干)

另一種經常遇到的字符串拼接

public string JoinIds(List<User> users){    StringBuilder sb = new StringBuilder();    foreach (var user in users)    {        sb.Append("'");        sb.Append(user.Id);        sb.Append("',");    }    sb.Length = sb.Length - 1;    return sb.ToString();}

對于這種情況有2中優化的方案

對于3.5以上可以直接使用Linq輔助,這種方案代碼少,但是性能相對差一些

public string JoinIds(List<User> users){    return "'" + string.Join("','", users.Select(it => it.Id)) + "'";}

對于非3.5或對性能要求極高的場合

public string JoinIds(List<User> users){    var ee = users.GetEnumerator();    StringBuilder sb = new StringBuilder();    if (ee.MoveNext())    {        sb.Append("'");        sb.Append(ee.Current.Id);        sb.Append("'");        while (ee.MoveNext())        {            sb.Append(",'");            sb.Append(ee.Current.Id);            sb.Append("'");        }    }    return sb.ToString();}

bool類型的判斷返回

這種現象常見于新手程序員中

//寫法1if(state == 1){    return true;}else{    return false;}//寫法2return state == 1 ? true : false;//優化后return state == 1;

類型的判斷

一般類型的判斷有2種形式

1,這種屬于代碼比較好寫,但是性能比較低, 原因就是GetType()的時候消耗了很多時間

Type type = obj.GetType();switch (type.Name){    case "Int32":        break;    case "String":        break;    case "Boolean":        break;    case "DateTime":        break;    ...    ...    default:        break;}

2,這種屬性寫代碼麻煩,但是性能很高的類型

if (obj is string){}else if (obj is int){}else if (obj is DateTime){}......else{}

其實有個中間之道,既可以保證性能又可以比較好寫

IConvertible conv = obj as IConvertible;if (conv != null){    switch (conv.GetTypeCode())    {        case TypeCode.Boolean:            break;        case TypeCode.Byte:            break;        case TypeCode.Char:            break;        case TypeCode.DBNull:            break;        case TypeCode.DateTime:            break;        case TypeCode.Decimal:            break;        case TypeCode.Double:            break;        case TypeCode.Empty:            break;        case TypeCode.Int16:            break;        case TypeCode.Int32:            break;        ...        ...        default:            break;    }}else{    //處理其他類型}

大部分情況下 這個是可以用的 如果你自己有個類型實現了IConvertible,然后返回TypeCode.Int32 就不再這個討論范圍之內了

使用枚舉作為索引

下面這個是一個真實的例子,為了突出重點,做了部分修改,刪除了多余的分支,源代碼中不只4個

enum TemplateCode{    None = 0,    Head = 1,    Menu = 2,    Foot = 3,    Welcome = 4,}public string GetHtml(TemplateCode tc){    switch (tc)    {        case TemplateCode.Head:            return GetHead();        case TemplateCode.Menu:            return GetMenu();        case TemplateCode.Foot:            return GetFoot();        case TemplateCode.Welcome:            return GetWelcome();        default:            throw new ArgumentOutOfRangeException("tc");    }}

優化后

readonly static Func<string>[] GetTemplate = InitTemplateFunction();private static Func<string>[] InitTemplateFunction(){    var arr = new Func<string>[5];    arr[1] = GetHead;    arr[2] = GetMenu;    arr[3] = GetFoot;    arr[4] = GetWelcome;
return arr;}
public string GetHtml(TemplateCode tc){ var index = (int)tc; if (index >= 1 && index <= 4) { return GetTemplate[index](); } throw new ArgumentOutOfRangeException("tc");}

不過有的時候,枚舉不一定都是連續的數字,那么也可以使用Dictionary

readonly static Dictionary<TemplateCode, Func<string>> TemplateDict = InitTemplateFunction();private static Dictionary<TemplateCode, Func<string>> InitTemplateFunction(){    var ditc = new Dictionary<TemplateCode, Func<string>>();    ditc.Add(TemplateCode.Head, GetHead);    ditc.Add(TemplateCode.Menu, GetMenu);    ditc.Add(TemplateCode.Foot, GetFoot);    ditc.Add(TemplateCode.Welcome, GetWelcome);    return ditc;} public string GetHtml(TemplateCode tc){    Func<string> func;    if (TemplateDict.TryGetValue(tc,out func))    {        return func();    }    throw new ArgumentOutOfRangeException("tc");}

這種優化在分支比較多的時候很好用,少的時候作用有限

字符類型Char,分支判斷時的處理技巧

這部分內容比較復雜,而且適用范圍有限,如果平時用不到的就可以忽略了

在處理字符串對象的時候,有時會需要判斷char的值然后做進一步的操作

public string Show(char c){    if (c >= '0' && c <= '9')    {        return "數字";    }    else if (c >= 'a' && c <= 'z')    {        return "小寫字母";    }    else if (c >= 'A' && c <= 'Z')    {        return "大寫字母";    }    else if (c == '/' || c == '//' || c == '|'        || c == '$' || c == '#' || c == '+'        || c == '%' || c == '&' || c == '-'        || c == '^' || c == '*' || c == '=')    {        return "特殊符號";    }    else if (c == ',' || c == '.' || c == '!'        || c == ':' || c == ';' || c == '?'        || c == '"' || c == '/'')    {        return "標點符號";    }    else    {        return "其他";    }}

這里有一種空間換時間的優化方式, 雖說是空間換時間,但是實際浪費的空間不會很多,因為char最多只有65536長度

readonly static byte[] CharMap = InitCharMap();private static byte[] InitCharMap(){    var arr = new byte[char.MaxValue];    for (char i = '0'; i <= '9'; i++)    {        arr[i] = 1;    }    for (char i = 'a'; i <= 'z'; i++)    {        arr[i] = 2;    }    for (char i = 'A'; i <= 'Z'; i++)    {        arr[i] = 3;    }    arr['/'] = 4;    arr['//'] = 4;    arr['|'] = 4;    arr['$'] = 4;    arr['#'] = 4;    arr['+'] = 4;    arr['%'] = 4;    arr['&'] = 4;    arr['-'] = 4;    arr['^'] = 4;    arr['*'] = 4;    arr['='] = 4;    arr[','] = 5;    arr['.'] = 5;    arr['!'] = 5;    arr[':'] = 5;    arr[';'] = 5;    arr['?'] = 5;    arr['"'] = 5;    arr['/''] = 5;    return arr;}public string Show(char c){    switch (CharMap[c])    {        case 0:            return "其他";        case 1:            return "數字";        case 2:            return "小寫字母";        case 3:            return "大寫字母";        case 4:            return "特殊符號";        case 5:            return "標點符號";        default:            return "其他";    }}

原先僅特殊符號一部分就需要判斷12次,修改過后只判斷一次就可以得到結果了

這方面的栗子在我的Json組件(代碼)(文章1,2,3)中也有使用

/// <summary>/// <para>包含1: 可以為頭的字符</para>/// <para>包含2: 可以為單詞的字符</para>/// <para>包含4: 可以為數字的字符</para>/// <para>等于8: 空白字符</para>/// <para>包含16:轉義字符</para>/// <para></para>/// </summary>private readonly static byte[] _WordChars = new byte[char.MaxValue];private readonly static sbyte[] _UnicodeFlags = new sbyte[123];private readonly static sbyte[, ,] _DateTimeWords;static UnsafeJsonReader(){    for (int i = 0; i < 123; i++)    {        _UnicodeFlags[i] = -1;    }    _WordChars['-'] = 1 | 4;    _WordChars['+'] = 1 | 4;    _WordChars['$'] = 1 | 2;    _WordChars['_'] = 1 | 2;    for (char c = 'a'; c <= 'z'; c++)    {        _WordChars[c] = 1 | 2;        _UnicodeFlags[c] = (sbyte)(c - 'a' + 10);    }    for (char c = 'A'; c <= 'Z'; c++)    {        _WordChars[c] = 1 | 2;        _UnicodeFlags[c] = (sbyte)(c - 'A' + 10);    }    _WordChars['.'] = 1 | 2 | 4;    for (char c = '0'; c <= '9'; c++)    {        _WordChars[c] = 4;        _UnicodeFlags[c] = (sbyte)(c - '0');    }    //科學計數法    _WordChars['e'] |= 4;    _WordChars['E'] |= 4;    _WordChars[' '] = 8;    _WordChars['/t'] = 8;    _WordChars['/r'] = 8;    _WordChars['/n'] = 8;    _WordChars['t'] |= 16;    _WordChars['r'] |= 16;    _WordChars['n'] |= 16;    _WordChars['f'] |= 16;    _WordChars['0'] |= 16;    _WordChars['"'] |= 16;    _WordChars['/''] |= 16;    _WordChars['//'] |= 16;    _WordChars['/'] |= 16;    string[] a =  { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };    string[] b =  { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };    _DateTimeWords = new sbyte[23, 21, 25];    for (sbyte i = 0; i < a.Length; i++)    {        var d = a[i];        _DateTimeWords[d[0] - 97, d[1] - 97, d[2] - 97] = (sbyte)(i + 1);    }    for (sbyte i = 0; i < b.Length; i++)    {        var d = b[i];        _DateTimeWords[d[0] - 97, d[1] - 97, d[2] - 97] = (sbyte)-(i + 1);    }    _DateTimeWords['g' - 97, 'm' - 97, 't' - 97] = sbyte.MaxValue;}
摘取部分blqw.Json的代碼

結束了...還要后續嗎?...貌似我又要懶一段時間


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲乱亚洲乱妇无码| 国产欧美一区二区三区在线| 欧美激情视频一区二区三区不卡| 国产精品久久999| 国产一区二区动漫| 精品国产91乱高清在线观看| 情事1991在线| 国产成人精品999| 亚洲欧美中文日韩v在线观看| 91成人福利在线| 亚洲国产另类 国产精品国产免费| 欧美精品一区在线播放| 欧美亚州一区二区三区| 亚洲欧美综合精品久久成人| 欧洲成人在线观看| 欧美精品一区二区三区国产精品| 亚洲男人的天堂在线播放| 国产美女精彩久久| 久久亚洲精品视频| 最近2019中文字幕一页二页| 亚洲最新视频在线| 亚洲激情第一页| 国产精品老女人精品视频| 激情av一区二区| 国产精品电影网站| 精品国产一区二区三区在线观看| 免费不卡欧美自拍视频| 国产精品一香蕉国产线看观看| 日本成人在线视频网址| 综合网中文字幕| 人人做人人澡人人爽欧美| 亚洲精品美女久久久久| 欧美色道久久88综合亚洲精品| 日韩精品视频在线观看网址| 国产精品美腿一区在线看| 色妞一区二区三区| 国产精品一区二区久久| 欧美性高潮在线| 精品久久久国产精品999| 久久天天躁狠狠躁夜夜爽蜜月| 日本精品免费一区二区三区| 久久精品这里热有精品| 91日本在线视频| 欧美日韩日本国产| 狠狠躁夜夜躁人人躁婷婷91| 欧美猛男性生活免费| 国产成人啪精品视频免费网| 国产精品对白刺激| 少妇久久久久久| 欧美一区二区三区四区在线| 精品少妇v888av| 亚洲精品av在线| 国产自摸综合网| 国产日韩欧美电影在线观看| 亚洲影院色无极综合| 亚洲天堂av女优| 欧美成人合集magnet| 国产成人精品免费久久久久| 色偷偷av亚洲男人的天堂| 精品无码久久久久久国产| 日日狠狠久久偷偷四色综合免费| 国自产精品手机在线观看视频| 欧美激情在线播放| 国产精品视频网| 色琪琪综合男人的天堂aⅴ视频| 欧美一级视频一区二区| 国产精品稀缺呦系列在线| 国产精品视频999| 欧美壮男野外gaytube| 在线观看久久久久久| 久久av红桃一区二区小说| 国产精品99久久久久久白浆小说| 日韩专区中文字幕| 日韩电影大片中文字幕| 日韩在线免费高清视频| 欧美福利视频在线| 中文字幕av一区二区| 国产69精品久久久久9999| 亚洲第一视频在线观看| www.欧美视频| 久久天天躁狠狠躁夜夜av| 欧美—级a级欧美特级ar全黄| 亚洲va国产va天堂va久久| 久久久久久久久久久免费精品| 国产91精品视频在线观看| 亚洲男女性事视频| 国产成人一区二区| 欧美有码在线视频| 亚洲国产天堂久久综合网| 亚洲人在线视频| 精品国产老师黑色丝袜高跟鞋| 性色av一区二区三区在线观看| 亚洲天堂av电影| 欧美理论片在线观看| 久久久久女教师免费一区| 亚洲一区二区中文| 欧美影院在线播放| 国自产精品手机在线观看视频| 日韩的一区二区| 日韩视频在线一区| 国内精品在线一区| 国产一区二区在线播放| 久久国产精品久久久久久久久久| 欧美成人h版在线观看| 午夜剧场成人观在线视频免费观看| 午夜精品久久久久久久99热浪潮| 久久中文字幕一区| 91免费视频国产| 正在播放欧美一区| 欧美日韩成人在线播放| 国产999精品久久久影片官网| 亚洲精品国产免费| 亚洲国语精品自产拍在线观看| 亚洲一区中文字幕在线观看| 韩曰欧美视频免费观看| 一区二区在线视频播放| 国产成人极品视频| 97色在线观看免费视频| 欧美中文字幕在线播放| 精品少妇v888av| 亚洲综合自拍一区| 91精品综合久久久久久五月天| 亚洲午夜未满十八勿入免费观看全集| 午夜精品理论片| 欧美噜噜久久久xxx| 国产成+人+综合+亚洲欧洲| 亚洲福利在线观看| 国产有码在线一区二区视频| 日韩精品免费综合视频在线播放| 亚洲欧洲自拍偷拍| 日产精品久久久一区二区福利| 国产免费一区视频观看免费| 在线成人激情黄色| 91精品国产综合久久久久久蜜臀| 黑人巨大精品欧美一区二区免费| 91丝袜美腿美女视频网站| 91精品啪在线观看麻豆免费| 亚洲精品久久久久久久久久久| 九九热在线精品视频| 国产成人精品av在线| 日韩美女激情视频| 国产成人精品日本亚洲专区61| 668精品在线视频| 日韩av观看网址| 国产精品久久久av久久久| 日韩中文字幕亚洲| 91精品在线观看视频| 欧美激情区在线播放| 欧美高跟鞋交xxxxhd| 国产精品一区二区在线| 亚洲人精品午夜在线观看| 精品久久久国产精品999| 日韩激情视频在线播放| 欧美性受xxxx白人性爽| 日韩色av导航| 69av成年福利视频| 久热99视频在线观看| 中文字幕不卡在线视频极品| 国产成一区二区| 91禁外国网站| 92国产精品久久久久首页| 欧美在线国产精品| 色无极亚洲影院| 亚洲人在线观看|