C# PLINQ 內(nèi)存列表查詢優(yōu)化歷程
產(chǎn)品中(基于ASP.NET MVC開發(fā))需要經(jīng)常對藥品名稱及名稱拼音碼進行下拉匹配及結(jié)果查詢。為了加快查詢的速度,所以我最開始就將其加入內(nèi)存中(大約有六萬五千條數(shù)據(jù))。
下面附實體類。
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的運算,我們將LINQ表達式中的轉(zhuǎn)小寫操作優(yōu)化一下,先在緩存列表上做些動作,將名稱和搜索碼先轉(zhuǎn)小寫存儲。
下面為改進過的實體類。
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多核的處理能力,提高運算效率,但是不一定是成倍的
LIST等泛型啟用并行計算很簡單,使用AsParallel()即可,改進如下:
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左右。
當然,寫到這里,大家以為這次的優(yōu)化就結(jié)束了,至少我當時是這么想的。
---------------------------------------------------------------------------------------------------
但是事實上,碰到了一個大麻煩。
由于產(chǎn)品運行于服務器IIS上面,使用AsParallel并行特性時(默認情況下,到底使用多少個線程來執(zhí)行PLINQ是在程序運行時由TPL決定的。但是,如果你需要限制執(zhí)行PLINQ查詢的線程數(shù)目(通常需要這么做的原因是有多個用戶同時使用系統(tǒng),為了服務器能同時服務盡可能多的用戶,必須限制單個用戶占用的系統(tǒng)資源),我們可以使用ParallelEnumerable. WithDegreeOfParallelism()擴展方法達到此目的。),客戶端一個請求就占用了過多的系統(tǒng)資源,導致應用程序池假死。無法提供服務。
我也嘗試過使用WithDegreeOfParallelism設置了一個相對較少的值,但是在使用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ā)時,應用程序池假死的問題。至此,困擾兩天的問題完美解決,雖然使用Parallel.For會帶來結(jié)果亂序的問題,但是結(jié)果數(shù)量已經(jīng)不多了,再次排序也沒有什么關(guān)系了。
具體原因參見下面:
ParallelOptions.MaxDegreeOfParallelism指明一個并行循環(huán)最多可以使用多少個線程。TPL開始調(diào)度執(zhí)行一個并行循環(huán)時,通常使用的是線程池中的線程,剛開始時,如果線程池中的線程很忙,那么,可以為并行循環(huán)提供數(shù)量少一些的線程(但此數(shù)目至少為1,否則并行任務無法執(zhí)行,必須阻塞等待)。等到線程池中的線程完成了一些工作,則分配給此并行循環(huán)的線程數(shù)目就可以增加,從而提升整個任務完成的速度,但最多不會超過ParallelOptions.MaxDegreeOfParallelism所指定的數(shù)目。
PLINQ的WithDegreeOfParallelism()則不一樣,它必須明確地指出需要使用多少個線程來完成工作。當PLINQ查詢執(zhí)行時,會馬上分配指定數(shù)目的線程執(zhí)行查詢。
之所以PLINQ不允許動態(tài)改變線程的數(shù)目,是因為許多PLINQ查詢是“級聯(lián)”的,為保證得到正確的結(jié)果,必須同步參與的多個線程。如果線程數(shù)目不定,則要實現(xiàn)線程同步非常困難。
有關(guān)C# PLINQ 內(nèi)存列表查詢優(yōu)化歷程小編就給大家介紹這么多,希望對大家有所幫助!
上一篇:C#常見的幾種集合 ArrayList,Hashtable,List&lt;T&gt;,
欄 目:C#教程
下一篇:基于C#實現(xiàn)網(wǎng)絡爬蟲 C#抓取網(wǎng)頁Html源碼
本文標題:C# PLINQ 內(nèi)存列表查詢優(yōu)化歷程
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6620.html
您可能感興趣的文章
- 01-10C#實現(xiàn)無限級聯(lián)下拉列表框
- 01-10C#獲取串口列表實現(xiàn)實時監(jiān)控串口
- 01-10C# 字符串string和內(nèi)存流MemoryStream及比特數(shù)組byte[]之間相互轉(zhuǎn)換
- 01-10詳解C#獲取特定進程CPU和內(nèi)存使用率
- 01-10C# 對象持久化詳解
- 01-10C#開發(fā)微信門戶及應用(4) 關(guān)注用戶列表及詳細信息管理
- 01-10詳解C#中的System.Timers.Timer定時器的使用和定時自動清理內(nèi)存應用
- 01-10C#.Net基于正則表達式抓取百度百家文章列表的方法示例
- 01-10Winform界面中實現(xiàn)菜單列表的動態(tài)個性化配置管理方法
- 01-10C#中event內(nèi)存泄漏總結(jié)


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已
隨機閱讀
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10C#中split用法實例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 04-02jquery與jsp,用jquery
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10delphi制作wav文件的方法
- 01-10SublimeText編譯C開發(fā)環(huán)境設置