LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#慎用ToLower和ToUpper,小心把你的系統(tǒng)給拖垮了

admin
2021年1月30日 9:44 本文熱度 3510

不知道何時(shí)開(kāi)始,很多程序員喜歡用ToLower,ToUpper去實(shí)現(xiàn)忽略大小寫(xiě)模式的字符串相等性比較,有可能這個(gè)習(xí)慣是從別的語(yǔ)言引進(jìn)的,大膽猜測(cè)下是JS,為了不引起爭(zhēng)論,我指的JS是技師的意思~

一:背景

1. 講故事

在我們一個(gè)訂單聚合系統(tǒng)中,每一筆訂單都會(huì)標(biāo)注來(lái)源,比如JD,Taobao,Etao,Shopex 等等一些渠道,UI上也提供高級(jí)配置輸入自定義的訂單來(lái)源,后來(lái)客戶反饋輸入xxx查詢不出訂單,這里就拿shopex為例,用戶用小寫(xiě)的shopex查詢,但系統(tǒng)中標(biāo)注的是首字母大寫(xiě)的Shopex,所以自然無(wú)法匹配,為了解決這個(gè)問(wèn)題開(kāi)發(fā)小哥就統(tǒng)一轉(zhuǎn)成大寫(xiě)做比對(duì),用代碼表示如下:

var orderfrom = "shopex".ToUpper(); customerIDList = MemoryOrders.Where(i =>i.OrderFrom.ToUpper()==orderFrom) .Select(i => i.CustomerId).ToList();

改完后就是這么牛的上線了,乍一看也沒(méi)啥問(wèn)題,結(jié)果一查詢明顯感覺(jué)比之前速度慢了好幾秒,干脆多點(diǎn)幾下,好咯。。。在監(jiān)控中發(fā)現(xiàn)CPU和memory突高突低,異常波動(dòng),這位小哥又在寫(xiě)bug了,查了下代碼問(wèn)他為什么這么寫(xiě),小哥說(shuō)在js中就是這么比較的~~~

2. string.Compare 改造

其實(shí)在C#中面對(duì)忽略大小寫(xiě)形式的比較是有專門的方法,性能高而且還不費(fèi)內(nèi)存,它就是 string.Compare,所以把上面代碼改成如下就可以了。

var orderfrom = "shopex"; customerIDList = MemoryOrders.Where(string.Compare(i.TradeFrom, tradefrom, StringComparison.OrdinalIgnoreCase) == 0) .Select(i => i.CustomerId).ToList();

這其中的 StringComparison.OrdinalIgnoreCase枚舉就是用來(lái)忽略大小寫(xiě)的,上線之后除了CPU還是有點(diǎn)波動(dòng),其他都沒(méi)有問(wèn)題了。

二:為什么ToLower,ToUpper會(huì)有如此大的影響

為了方便演示,我找了一篇英文小短文,然后通過(guò)查詢某一個(gè)單詞來(lái)演示ToUpper為啥對(duì)cpu和memory以及查詢性能都有如此大的影響,代碼如下:

public static void Main(string[] args) { var strList = "Hooray! It''s snowing! It''s time to make a snowman.James runs out. He makes a big pile of snow. He puts a big snowball on top. He adds a scarf and a hat. He adds an orange for the nose. He adds coal for the eyes and buttons.In the evening, James opens the door. What does he see? The snowman is moving! James invites him in. The snowman has never been inside a house. He says hello to the cat. He plays with paper towels.A moment later, the snowman takes James''s hand and goes out.They go up, up, up into the air! They are flying! What a wonderful night!The next morning, James jumps out of bed. He runs to the door.He wants to thank the snowman. But he''s gone.".Split('' ''); var query = "snowman".ToUpper(); for (int i = 0; i < strList.Length; i++) { var str = strList[i].ToUpper(); if (str == query) Console.WriteLine(str); } Console.ReadLine(); }

1. 內(nèi)存波動(dòng)探究

既然內(nèi)存有波動(dòng),說(shuō)明內(nèi)存里進(jìn)了臟東西,學(xué)C#基礎(chǔ)知識(shí)的時(shí)候應(yīng)該知道string是不可變的,一旦有修改就會(huì)生成新的string,那就是說(shuō)ToUpper之后會(huì)出現(xiàn)新的string,為了用數(shù)據(jù)佐證,用windbg演示一下。

0:000> !dumpheap -type System.String -stat Statistics: MT Count TotalSize Class Name 00007ff8e7a9a120 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]] 00007ff8e7a99e98 1 80 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]] 00007ff8e7a9a378 1 96 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]][] 00007ff8e7a93200 19 2264 System.String[] 00007ff8e7a959c0 429 17894 System.String Total 451 object

可以看到托管堆上有Count=429個(gè)string對(duì)象,那這個(gè)429怎么來(lái)的? 組成:短文128個(gè),ToUpper后128個(gè),系統(tǒng)默認(rèn)165個(gè),query字符串2個(gè),不明字符串6個(gè),最后就是128 +128 + 165 + 2 + 6=429,然后隨便抽幾個(gè)看看。

!dumpheap -mt 00007ff8e7a959c0 > !DumpObj 000002244282a1f8

0:000> !DumpObj /d 0000017800008010 Name: System.String MethodTable: 00007ff8e7a959c0 EEClass: 00007ff8e7a72ec0 Size: 38(0x26) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: HOUSE. Fields: MT Field Offset Type VT Attr Value Name 00007ff8e7a985a0 4000281 8 System.Int32 1 instance 6 m_stringLength 00007ff8e7a96838 4000282 c System.Char 1 instance 48 m_firstChar 00007ff8e7a959c0 4000286 d8 System.String 0 shared static Empty >> Domain:Value 0000017878943bb0:NotInit << 0:000> !DumpObj /d 0000017800008248 Name: System.String MethodTable: 00007ff8e7a959c0 EEClass: 00007ff8e7a72ec0 Size: 40(0x28) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: SNOWMAN Fields: MT Field Offset Type VT Attr Value Name 00007ff8e7a985a0 4000281 8 System.Int32 1 instance 7 m_stringLength 00007ff8e7a96838 4000282 c System.Char 1 instance 53 m_firstChar 00007ff8e7a959c0 4000286 d8 System.String 0 shared static Empty >> Domain:Value 0000017878943bb0:NotInit <<

查了兩個(gè)全是大寫(xiě)的“HOUSE”,“SNOWMAN”,再回到我的場(chǎng)景有小百萬(wàn)訂單,也就會(huì)在托管堆上生成小百萬(wàn)個(gè)string,如果再點(diǎn)一次又會(huì)生成小百萬(wàn)個(gè),內(nèi)存怎么會(huì)不突增呢。。。

2.cpu和查詢時(shí)間探究

現(xiàn)在大家知道了堆上可能有幾百萬(wàn)個(gè)string對(duì)象,這些對(duì)象的分配和釋放給cpu造成了不小的壓力,本身toUpper之后速度變慢,更慘的是還會(huì)造成gc顫抖式觸發(fā),一顫抖所有的thread都會(huì)被暫停開(kāi)啟回收,速度就更慢了。。。

三:string.Compare解析

再回過(guò)頭來(lái)看一下string.Compare為什么這么🐮👃,大家可以通過(guò)dnspy查看一下源碼即可,里面有一個(gè)核心函數(shù),如下圖:

// Token: 0x060004B8 RID: 1208 RVA: 0x00010C48 File Offset: 0x0000EE48 [SecuritySafeCritical] private unsafe static int CompareOrdinalIgnoreCaseHelper(string strA, string strB) { int num = Math.Min(strA.Length, strB.Length); fixed (char* ptr = &strA.m_firstChar) { fixed (char* ptr2 = &strB.m_firstChar) { char* ptr3 = ptr; char* ptr4 = ptr2; while (num != 0) { int num2 = (int)(*ptr3); int num3 = (int)(*ptr4); if (num2 - 97 <= 25) { num2 -= 32; } if (num3 - 97 <= 25) { num3 -= 32; } if (num2 != num3) { return num2 - num3; } ptr3++; ptr4++; num--; } return strA.Length - strB.Length; } } }

這段代碼很精妙,巧妙的使用97,將兩個(gè)字符串按照大寫(xiě)模式的ascii碼進(jìn)行逐一比較,相比在堆上搞一堆東西快捷的多。

然后我修改一下代碼,看看此時(shí)堆上如何。。。

public static void Main(string[] args) { ... var query = "snowman"; for (int i = 0; i < strList.Length; i++) { if (string.Compare(strList[i], query, StringComparison.OrdinalIgnoreCase) == 0) { Console.WriteLine(strList[i]); } } Console.ReadLine(); } 0:000> !dumpheap -type System.String -stat Statistics: MT Count TotalSize Class Name 00007ff8e7a9a120 1 24 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]] 00007ff8e7a99e98 1 80 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]] 00007ff8e7a9a378 1 96 System.Collections.Generic.Dictionary`2+Entry[[System.String, mscorlib],[System.Globalization.CultureData, mscorlib]][] 00007ff8e7a93200 19 2264 System.String[] 00007ff8e7a959c0 300 13460 System.String Total 322 objects

從 System.String 中可以看到,現(xiàn)在的堆上是300個(gè),而原來(lái)是429,相當(dāng)于少了129個(gè),也就是128個(gè)ToUpper加上1個(gè)Query中的ToUpper被消滅掉了。

四: 總結(jié)

平時(shí)我們哪些不好的寫(xiě)法,在大量數(shù)據(jù)面前不堪一擊,同時(shí)也是一次好的成長(zhǎng)機(jī)會(huì)~


該文章在 2021/1/30 9:44:09 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
日本片高潮在线观看 | 日韩经典亚洲一区二区三区 | 日韩中文字幕在线综合网 | 亚洲日韩欧美综合中文字幕 | 一本大道AV伊人久久综合 | 熟女丰满少妇精品一区二区 |