共计 1594 个字符,预计需要花费 4 分钟才能阅读完成。
背景
开始
故事的开始因为在工作中遇到一个需要去解决加载数据十分慢的问题, 要害程序是曾经在生产环境运行了相当长一段时间的,按情理来说是不会有问题, 至多从线上运行的稳定性来说。
个人观点
在这里仅作为开发小结记录一下, 谁写的和为什么这样写的问题, 不在此次记录总结范畴之内, 只针对代码做出剖析,如果您看了感觉或者曾经有更好的方法,烦请通知我一下,咱们能够独特探讨,如果有中央不对, 也请不吝斧正。
为什么要记录下来?
做任何事件都要有产出,日常开发也一样,除了交付工作, 还应有本人的总结, 以利于本人后续复盘,产出不在于多少,几行文字、一个表格或者画一幅图。产出也不在于 100% 能搞懂开发中的每一个问题,把看不懂的总结进去,也是产出。
后续解决的问题或没解决的都在这里总结记录,此前解决过的也会陆续从新总结
找到起因
通过一番调试定位到代码之后,找到了问题次要分 2 类:
1. 反复求值
这个很好了解,就是下面曾经获得雷同操作后果, 或者能够获得雷同操作后果存入变量,然而此处并没有这个做而是
每一次都执行须要求值的表达式去失去后果, 大大的升高了执行效率和进步了资源占用
2. 循环嵌套
鉴于波及公司代码,不不便贴出,为了更加活泼的形容具体问题,上面是我依据问题形象出的代码 Demo 和形容如下:
1). 循环 500 次,对应的 list 汇合中有 50W 条数据
2). 依据 Lambda 找到 ProductId 为 213000 的数据,而后存入 result 汇合
依据下面的示例代码能够发现,在循环中,又应用了循环,暂且不思考
ForEach 是否是多线程或者它和 foreach 以及 for 的执行效率, 为什么说又应用了循环呢?通过排查发现导致问题的外围的
起因就是外部的 Lambda 表达式求值, 为什么求值慢呢?特意查看了源码并且查看相干参考资料,因为 Lambda 就是循环实现的,只不过退出了迭代器和状态机这样一些的提早
机制, 即便这样它仍然会影响效率。如果从数据结构的角度形象来剖析,此处工夫复杂度就是 O(500*50w) 随着次数增大, 执行工夫就是越来越大的增长。
3. 验证执行工夫
验证执行工夫为:1195 毫秒, 如果在外层再加一层循环呢?
汇合操作皆可 Lambda?
鉴于曾经找到了问题所在, 下一步就要着手解决的办法了,第一个问题好解决, 扭转一下求值写法就好了。
次要是第二个问题的解决, 在解决问题之前失去了一个很重要的的论断 那就是 "Lambda 并不实用所有中央, 反而有时会让你的程序更蹩脚"
看了下面的例子是不是深有体会。
解决方案
-
如何优化 lambda(循环)?
咱们要思考问题的实质是在这里对 list 怎么查找比程序循环快, 在数据结构中程序表查找分为三类:
1. 程序查找 2. 二分查找 3. 索引查找
如何抉择对应查找优化, 这里的重点就是要将工夫复杂度从 O(n) 或者 O(10x500x50w) 转为 O(1),毫无疑问在这抉择索引查找,因为依据索引下标拜访元素的工夫复杂度为 O(1), 那索引查找必然优于程序查找的,接下来如何变为索引查找呢?
咱们不禁会问:” 在这里恰好是索引下标跟 ProductId 对上了能力找到,那如果是乱的呢 ”? 那就须要变通一下, 就是变为字典汇合,依据键找到值
对于无反复数据的汇合来说咱们先转为 Dictionary 再看执行工夫, 虽比不上索引, 然而跟循环比呢?
到这里咱们还须要思考, 这里因为 ProductId 是不反复的你才能够加到
Dictionary,如果有反复的咋整? 别慌有方法,就是:
对于有反复数据的汇合来说咱们能够应用 ILookup, 因为他会把雷同键分组应用一个 Key
总结
1. 语法糖和开发库的确很不错, 然而对于保护来说,可能会造成肯定的阻碍。2. 在日常开发中, 尽管当初有很多的库供咱们调用, 在应用的过程中咱们应该去联合代码思考是否能够在特定的中央用
而不是一味的谋求语法糖的简略、离奇。