标签:代码 索引 查找 求值 Lambda 小结 循环 加载
背景
故事的开始因为在工作中遇到一个需求去解决加载数据非常慢的问题,关键程序是已经在生产环境运行了相当长一段时间的,按道理来说是不会有问题,至少从线上运行的稳定性来说。
个人观点
在这里仅作为开发小结记录一下,谁写的和为什么这样写的问题,不在此次记录总结范围之内,只针对代码做出分析,如果您看了觉得或者已经有更好的办法,烦请告诉我一下,我们可以共同讨论,如果有地方不对,也请不吝斧正,
为什么要记录下来?
做任何事情都要有产出,日常开发也一样,除了交付任务,还应有自己的总结,以利于自己后续复盘,产出不在于多少,几行文字、一个表格或者画一幅图,产出也不在于100%能搞懂开发中的每一个问题,把看不懂的总结出来,也是产出,后续解决的问题或没解决的都在这里总结记录,此前解决过的也会陆续重新总结.
定位原因
经过一番调试定位到代码之后,找到了问题主要分2类:
1.重复求值
这个很好理解,就是上面已经取得相同操作结果,或者可以取得相同操作结果存入变量,但是此处并没有这个做.
而是每一次都执行需要求值的表达式去得到结果,大大的降低了执行效率和提高了资源占用
2.循环嵌套
鉴于涉及公司代码,不方便贴出,为了更加生动的描述具体问题,下面是我根据问题抽象出的代码Demo和描述如下:
1).循环500次,对应的list集合中有50W条数据
2).根据Lambda找到ProductId为213000的数据,然后存入result集合
根据上面的示例代码可以发现,在循环中,又使用了循环,暂且不考虑ForEach是否是多线程或者它和foreach 以及for的执行效率,为什么说又使用了循环呢?经过排查发现导致问题的核心的原因就是内部的Lambda表达式求值,那为什么求值慢呢?
查看相关参考资料,因为Lambda就是循环实现的,加入了迭代器和状态机这样的一些的延迟机制,但是此处直接FirstOrDefault()了,那就会立即计算,并且不会延迟加载.
如果从数据结构的角度抽象来分析,此处时间复杂度就是O(500*50w) 随着次数增大,执行时间就是越来越大的增长.
3.验证执行时间
验证执行时间为:1195毫秒,如果在外层再加一层循环呢?
是否集合操作皆可Lambda?
已经找到了问题所在,下一步就要着手解决的方法了,第一个问题好解决,改变一下求值写法不要重复求值就好了.
主要是第二个问题的解决,在解决问题之前得到了一个很重要的的结论,那就是"Lambda并不适用所有地方,反而有时不恰当的使用会让你的程序更糟糕"
看了上面的例子是不是深有体会.
解决方案
1.如何优化lambda(循环)?
我们要思考问题的本质是在这里对list怎么查找比顺序循环快,在数据结构中顺序表查找分为三类:
1.顺序查找
2.二分查找
3.索引查找
如何选择对应查找优化,这里的重点就是要将时间复杂度从O(n)或者O(10x500x50w)转为O(1),毫无疑问在这选择索引查找,因为根据索引下标访问元素的时间复杂度为O(1),那索引查找必定优于顺序查找的,接下来如何变为索引查找呢?
我们不禁会问:"在这里恰好是索引下标跟ProductId对上了才能找到,那如果是乱的呢"? 那就需要变通一下,就是变为字典集合,根据键找到值.
对于无重复数据的集合来说我们先转为Dictionary再看执行时间,虽比不上索引但是跟循环比呢?
到这里我们还需要思考,这里因为ProductId是不重复的你才可以加到
Dictionary,如果有重复的咋整?别慌有办法,那就是:
针对有重复数据的集合来说我们可以使用ILookup,因为他会把相同键分组使用一个Key.
简单总结
- 语法糖和开发库确实很不错,但是对于维护来说,会造成一定的障碍。
- 在日常开发中,虽然现在有很多的库供我们调用,在使用的过程中我们应该去结合代码思考是否可以在特定的地方用而不是一味的追求语法糖的简单、新奇。
标签:代码,索引,查找,求值,Lambda,小结,循环,加载 来源: https://www.cnblogs.com/yuxl01/p/15225066.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。