当前位置: 首页 > 科技观察

你以为前端不需要懂算法?然后看这个实战例子

时间:2023-03-19 21:49:01 科技观察

算法就是问题的求解步骤。同一个问题可以有很多解法,算法也会有很多,但是算法有好有坏,区分的标志就是复杂度。耗时/内存使用的性能可以通过复杂度来估计,所以我们用复杂度来评价算法。(不知道复杂度的可以看这篇文章:性能分析不需要Profiler,复杂度分析也行。)在开发的时候,大部分场景下,我们用最简单的思路,就是,复杂度比较高的算法没问题。这个问题,好像各种高端算法都用不到。算法似乎是可学习的或不可学习的。其实不是,那是因为你没有遇到过一些数据量很大的场景。举个我之前公司的一个具体场景的例子:一个体现算法威力的例子这是我之前公司高德的一个真实的例子。我们将对整个源代码进行依赖分析。将有数以万计的模块。一个模块依赖于另一个模块的称为前向依赖,而一个模块依赖于另一个模块的称为反向依赖。我们先分析正向依赖,再分析反向依赖。在分析反向依赖的时候,之前的思路是这样的。对于每一个依赖,它遍历一侧的所有模块,找到依赖它的模块。这就是它的反向依赖。这个想法很简单,很容易想到,但是这个想法有什么问题吗?该算法的复杂度为O(n^2)。如果n达到几十万,性能会很差。从复杂度我们可以估算一下。事实上,确实是这样的。后来跑完整个源码依赖,我们花了10多个小时,连一晚上都跑不起来。如果让你优化,你会如何优化性能?可能有同学会问,能不能拆分成多个进程/多个工作线程,把依赖分析的任务拆分成几个部分,这样可以得到几倍的性能提升。是的,好几次提升都很大。但是如果说我们后来改了,性能直接提升了几万倍你信吗?我们的改法是这样的:在分析反向依赖之前,每个依赖都要遍历所有的正向依赖。但实际上,正向依赖不就是反向依赖吗?所以我们在分析正向依赖的时候直接改成记录反向依赖。这样就不需要单独分析反向依赖,算法复杂度从O(n^2)降低到O(n)。从O(n^2)到O(n)的变化,相当于在模块数万个的情况下,性能提升了数万倍。这体现在之前我们要跑一个晚上的代码,现在十分钟就跑完了。您认为这种级别的优化可以通过单独运行多个线程/进程来实现吗?这就是算法的力量。当你想到复杂度更低的算法时,就意味着性能得到了极大的提升。就像我们为什么整天说diff算法,因为它把O(n^2)这种简单算法的复杂度降低到了O(n),也就是说当dom节点有几千个的时候,就会有几千个次性能改进。那么,你感受到算法的强大了吗?综上所述,多线程、缓存等手段最多能提升数倍的性能,而算法的优化直接将性能提升了一个数量级。当数据量很大时,性能会是数万倍。推动。那为什么我们平时会认为算法没用呢?那是因为你处理的数据量太小了,如果你处理几百个数据,你用O(n^2)O(n^3)和O(n)的算法,区别不大。你处理的场景数据量越大,这个算法的重要性就越高,因为好算法和差算法的区别不是几倍、几十倍那么简单,可能是几万倍。所以,你会看到各大公司都在测试算法,没有用吗?不,它太重要了,可以说决定了所写代码的性能。