产品中(基于ASP.NET MVC开发)需要经常对药品名称及名称拼音码进行下拉匹配及结果查询。为了加快查询的速度,所以我最开始就将其加入内存中(大约有六万五千条数据)。
下面附实体类。
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表达式中的转小写操作优化一下,先在缓存列表上做些动作,将名称和搜索码先转小写存储。
下面为改进过的实体类。
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左右。
虽然这样做,内存列表中会多一些冗余数据,但是得到的性能提升有一倍了。
第三次做法:
启用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左右。
当然,写到这里,大家以为这次的优化就结束了,至少我当时是这么想的。
---------------------------------------------------------------------------------------------------
但是事实上,碰到了一个大麻烦。
由于产品运行于服务器IIS上面,使用AsParallel并行特性时(默认情况下,到底使用多少个线程来执行PLINQ是在程序运行时由TPL决定的。但是,如果你需要限制执行PLINQ查询的线程数目(通常需要这么做的原因是有多个用户同时使用系统,为了服务器能同时服务尽可能多的用户,必须限制单个用户占用的系统资源),我们可以使用ParallelEnumerable. WithDegreeOfParallelism()扩展方法达到此目的。),客户端一个请求就占用了过多的系统资源,导致应用程序池假死。无法提供服务。
我也尝试过使用WithDegreeOfParallelism设置了一个相对较少的值,但是在使用LOADRUNNER来开启200个并发的时候,也会产生假死的情况,于是,不得不尝试下面第四步的办法。
第四次做法:
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);
时间与第三步没有什么区别,但是这样做解决了并发时,应用程序池假死的问题。至此,困扰两天的问题完美解决,虽然使用Parallel.For会带来结果乱序的问题,但是结果数量已经不多了,再次排序也没有什么关系了。
具体原因参见下面:
ParallelOptions.MaxDegreeOfParallelism指明一个并行循环最多可以使用多少个线程。TPL开始调度执行一个并行循环时,通常使用的是线程池中的线程,刚开始时,如果线程池中的线程很忙,那么,可以为并行循环提供数量少一些的线程(但此数目至少为1,否则并行任务无法执行,必须阻塞等待)。等到线程池中的线程完成了一些工作,则分配给此并行循环的线程数目就可以增加,从而提升整个任务完成的速度,但最多不会超过ParallelOptions.MaxDegreeOfParallelism所指定的数目。
PLINQ的WithDegreeOfParallelism()则不一样,它必须明确地指出需要使用多少个线程来完成工作。当PLINQ查询执行时,会马上分配指定数目的线程执行查询。
之所以PLINQ不允许动态改变线程的数目,是因为许多PLINQ查询是“级联”的,为保证得到正确的结果,必须同步参与的多个线程。如果线程数目不定,则要实现线程同步非常困难。
有关C# PLINQ 内存列表查询优化历程小编就给大家介绍这么多,希望对大家有所帮助!
问题内容: 这就是整个查询… 如果… 和… 有明显的理由吗? 正在服用? 扩展说明 问题答案: 您可以始终使用EXPLAIN或EXPLAIN EXTENDED 来查看MySql对查询所做的操作 您也可以用稍微不同的方式编写查询,是否尝试过以下方法? 看看效果如何会很有趣。我希望它会更快,因为目前,我认为MySql将为您拥有的每个节目运行内部查询1(这样一个查询将运行多次。联接应该更有效。) 如果希
通常用于App中展示当前用户的历史咨询列表,比如消息盒子的展示: 一、咨询列表说明: 1、获取所有咨询入口的最后一条消息的总和,以接待组settingid为维度; 2、能区分该条消息的状态(已读、未读以及未读数); 3、返回的数据是按照最后一条消息的时间对咨询列表倒序排序。 二、API接口 方法一:+ (NSArray *)ntalker_getConsultHistoryListCount:(N
问题内容: 我希望从我的用户模型中检索一些信息,如下所示: 在主页中,我有一个 位置 过滤器,您可以在其中浏览来自国家或城市的用户。 所有字段还包含其中的用户数: 在主页上,然后我还有“学生和老师”页面,我希望仅提供有关这些国家和城市有多少老师的信息… 我想做的是创建一个对MongoDB的查询,以通过单个查询检索所有这些信息。 此刻查询如下: 问题是我不知道如何获取所需的所有信息。 我不知道如何获
问题内容: 此查询需要153秒才能运行。中有数百万行。 我认为查询要花很长时间,因为where子句中的功能。但是,我需要在列上执行ltrim rtrim,而且日期也必须在格式上匹配。如何优化此查询? 说明计划: 首要的关键: 索引: 但是,在解释计划中,我看不到使用索引/主键。那是问题吗? 问题答案: 试试这个: 如果尚无时间,请从其外观(出生日期?)上删除该对象。除此之外,您还需要一些索引工作。
我有一个需要50秒的查询 security_tasks中的记录=841321 relations中的记录=234254 我能做些什么让它快一点,比如快1秒或2秒 有什么想法吗?
主要内容:概述,一、关联查询优化,1.左(右)外连接,2.内连接,3.JOIN语句原理,4.JOIN小结,5.Hash Join,二、子查询优化,三、排序优化,四、GROUP BY优化,五、优先考虑覆盖索引,六、使用前缀索引,七、索引下推ICP,八、其他查询优化,1.COUNT(*)与COUNT(具体字段)效率,2.不使用SELECT *,3.LIMIT 1优化,4.多使用commit概述 数据库调优的方式有多种: 建立索引、充分利用到索引、不让索引失效 对SQL语句进行优化 调优如缓冲、线程数