C# PLINQ 內(nèi)存列表查詢優(yōu)化歷程
產(chǎn)品中(基于ASP.NET MVC開發(fā))需要經(jīng)常對藥品名稱及名稱拼音碼進(jìn)行下拉匹配及結(jié)果查詢。為了加快查詢的速度,所以我最開始就將其加入內(nèi)存中(大約有六萬五千條數(shù)據(jù))。
下面附實(shí)體類。
public class drugInfo { public int drug_nameid { get; set; } public string drug_name { get; set; } public string drug_search_code { get; set; } }
第一次做法:
Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); key = key.ToLower(); var resultList = cacheList.Where(m => m.drug_name.ToLower().Contains(key) || m.drug_search_code.ToLower().Contains(key)).ToList(); stopWatch.Stop(); double eMseconds = Math.Max(0, stopWatch.Elapsed.TotalSeconds);
刷新頁面幾次,得到個平均用時約35MS左右。
第二次做法:
為了減少CPU的運(yùn)算,我們將LINQ表達(dá)式中的轉(zhuǎn)小寫操作優(yōu)化一下,先在緩存列表上做些動作,將名稱和搜索碼先轉(zhuǎn)小寫存儲。
下面為改進(jìn)過的實(shí)體類。
public class drugInfo { public int drug_nameid { get; set; } public string drug_name { get; set; } public string drug_search_code { get; set; } public string lower_drug_name { get; set; } public string lower_drug_search_code { get; set; } } Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); key = key.ToLower(); var resultList = cacheList.Where(m => m.lower_drug_name.Contains(key) || m.lower_drug_search_code.Contains(key)).ToList(); stopWatch.Stop(); double eMseconds = Math.Max(0, stopWatch.Elapsed.TotalSeconds); ViewBag.useTime = string.Format("用時{0}秒\r\n", eMseconds);
刷新頁面幾次,得到個平均用時約16MS左右。
雖然這樣做,內(nèi)存列表中會多一些冗余數(shù)據(jù),但是得到的性能提升有一倍了。
第三次做法:
啟用PLINQ的并行計算,并行計算是NET4.0的特性,可以利用CPU多核的處理能力,提高運(yùn)算效率,但是不一定是成倍的
LIST等泛型啟用并行計算很簡單,使用AsParallel()即可,改進(jìn)如下:
Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); key = key.ToLower(); var resultList = cacheList.AsParallel().Where(m => m.lower_drug_name.Contains(key) || m.lower_drug_search_code.Contains(key)).ToList(); stopWatch.Stop(); double eMseconds = Math.Max(0, stopWatch.Elapsed.TotalSeconds); ViewBag.useTime = string.Format("用時{0}秒\r\n", eMseconds);
同樣,我們多刷新頁面幾次,獲得的平均時間為10MS左右。
當(dāng)然,寫到這里,大家以為這次的優(yōu)化就結(jié)束了,至少我當(dāng)時是這么想的。
---------------------------------------------------------------------------------------------------
但是事實(shí)上,碰到了一個大麻煩。
由于產(chǎn)品運(yùn)行于服務(wù)器IIS上面,使用AsParallel并行特性時(默認(rèn)情況下,到底使用多少個線程來執(zhí)行PLINQ是在程序運(yùn)行時由TPL決定的。但是,如果你需要限制執(zhí)行PLINQ查詢的線程數(shù)目(通常需要這么做的原因是有多個用戶同時使用系統(tǒng),為了服務(wù)器能同時服務(wù)盡可能多的用戶,必須限制單個用戶占用的系統(tǒng)資源),我們可以使用ParallelEnumerable. WithDegreeOfParallelism()擴(kuò)展方法達(dá)到此目的。),客戶端一個請求就占用了過多的系統(tǒng)資源,導(dǎo)致應(yīng)用程序池假死。無法提供服務(wù)。
我也嘗試過使用WithDegreeOfParallelism設(shè)置了一個相對較少的值,但是在使用LOADRUNNER來開啟200個并發(fā)的時候,也會產(chǎn)生假死的情況,于是,不得不嘗試下面第四步的辦法。
第四次做法:
Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); key = key.ToLower(); ConcurrentBag<drugInfo> resultList = new ConcurrentBag<drugInfo>(); Parallel.For(0, cacheList.Count, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (i) => { var item = cacheList[i]; if (item.lower_drug_name.Contains(key) || item.lower_drug_search_code.Contains(key)) { resultList.Add(item); } }); stopWatch.Stop(); double eMseconds = Math.Max(0, stopWatch.Elapsed.TotalSeconds); ViewBag.useTime = string.Format("用時{0}秒\r\n", eMseconds);
時間與第三步?jīng)]有什么區(qū)別,但是這樣做解決了并發(fā)時,應(yīng)用程序池假死的問題。至此,困擾兩天的問題完美解決,雖然使用Parallel.For會帶來結(jié)果亂序的問題,但是結(jié)果數(shù)量已經(jīng)不多了,再次排序也沒有什么關(guān)系了。
具體原因參見下面:
ParallelOptions.MaxDegreeOfParallelism指明一個并行循環(huán)最多可以使用多少個線程。TPL開始調(diào)度執(zhí)行一個并行循環(huán)時,通常使用的是線程池中的線程,剛開始時,如果線程池中的線程很忙,那么,可以為并行循環(huán)提供數(shù)量少一些的線程(但此數(shù)目至少為1,否則并行任務(wù)無法執(zhí)行,必須阻塞等待)。等到線程池中的線程完成了一些工作,則分配給此并行循環(huán)的線程數(shù)目就可以增加,從而提升整個任務(wù)完成的速度,但最多不會超過ParallelOptions.MaxDegreeOfParallelism所指定的數(shù)目。
PLINQ的WithDegreeOfParallelism()則不一樣,它必須明確地指出需要使用多少個線程來完成工作。當(dāng)PLINQ查詢執(zhí)行時,會馬上分配指定數(shù)目的線程執(zhí)行查詢。
之所以PLINQ不允許動態(tài)改變線程的數(shù)目,是因?yàn)樵S多PLINQ查詢是“級聯(lián)”的,為保證得到正確的結(jié)果,必須同步參與的多個線程。如果線程數(shù)目不定,則要實(shí)現(xiàn)線程同步非常困難。
有關(guān)C# PLINQ 內(nèi)存列表查詢優(yōu)化歷程小編就給大家介紹這么多,希望對大家有所幫助!
相關(guān)文章
C# 整數(shù)轉(zhuǎn)二進(jìn)制字符串方式
這篇文章主要介紹了C# 整數(shù)轉(zhuǎn)二進(jìn)制字符串方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02C#使用GDI+實(shí)現(xiàn)生成驗(yàn)證碼
這篇文章介紹了C#使用GDI+實(shí)現(xiàn)生成驗(yàn)證碼的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05