前面我们学习了那么多的算法,大家也知道,算法的目的是为了解决实际问题的。但我们也看到,对于同一个问题,我们可以用不同的算法来解决。而因为时间和空间复杂度的问题,不同的算法执行的效率差距还是比较大的。我们学习算法,当然是希望能找到一种最高效的算法。
那么,我们思考一个问题,如果一个问题已经用一个很精妙的算法解决了,但还想进一步、大幅度提高效率,这有可能吗?
我们可以考虑更优秀的算法来实现,但如果在算法不变的情况下,是不是就没有办法了呢?其实还是有办法的。这里我们可以使用我们前面学过的分治算法思想,把一个大的问题拆分成很多相似的小问题,每个小问题,交给不同的线程甚至不同的物理机去执行,执行完毕再做一次归并处理,这样就能极大地利用硬件的资源,几倍十几倍地提高执行效率。分治算法在工程上也也可以称为“并行算法”。下面以一些具体的案例来对并行算法进行介绍。
一、并行处理海量日志
问题:海量日志数据,如何提取出某日访问百度次数最多的那个IP?
分析:百度作为国内第一大搜索引擎,每天访问它的IP数量巨大,如果想一次性把所有IP数据装进内存处理,则内存容量明显不够,故针对数据太大,内存受限的情况,可以把大文件转化成(取模映射)小文件,从而大而化小,逐个处理。
换言之,先映射,而后统计,最后排序。
解法:具体分为以下3个步骤
- 分而治之/hash映射
- 首先把这一天访问百度日志的所有IP提取出来,然后逐个写入到一个大文件中,接着采用哈希取模的方式,比如%1000,把整个大文件映射为1000个小文件。
- hash_map统计
- 当大文件转化成了小文件,那么我们便可以采用hash_map(ip, value)来分别对1000个小文件中的IP进行频率统计,再找出每个小文件中出现频率最大的IP。
- 堆/快速排序
- 统计出1000个频率最大的IP后,依据各自频率的大小进行排序(可采取堆排序),找出那个频率最大的IP,即为所求。
二、并行处理大文件
问题:有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回词频最高的100个词。
解法:
- 分而治之/hash映射
- 顺序读取文件,对于每个词x,取hash(x)%5000,然后把该值存到5000个小文件(记为x0,x1,...x4999)中。这样每个文件大概是200k左右。当然,如果其中有的小文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M。
- hash_map统计
- 对每个小文件,采用trie树/hash_map等统计每个文件中出现的词以及相应的频率。
- 堆/归并排序
- 取出出现频率最大的100个词(可以用含100个结点的最小堆)后,再把100个词及相应的频率存入文件,这样又得到了5000个文件。最后就是把这5000个文件进行归并(类似于归并排序)的过程了。
三、并行计算TopN
问题;海量数据分布在100台服务器中,请高效统计出这批数据的TOP10。
- 堆排序
- 在每台电脑上求出TOP 10,可以采用包含10个元素的堆完成(TOP 10小,用最大堆,TOP 10大,用最小堆,比如求TOP10大,我们首先取前10个元素调整成最小堆,如果发现,然后扫描后面的数据,并与堆顶元素比较,如果比堆顶元素大,那么用该元素替换堆顶,然后再调整为最小堆。最后堆中的元素就是TOP 10大)。
- 组合归并
- 求出每台电脑上的TOP 10后,然后把这100台电脑上的TOP 10组合起来,共1000个数据,再利用上面类似的方法求出TOP 10就可以了。
四、并行算法在ElasticSearch的分页中的应用及深度分页问题
众所周知,在ES这样的系统中,因为数据量巨大,记录都是存放在不同分片上的,我们如果要对查询的结果集进行分页,那就需要先从每个分片上取一部分数据,再进行聚合,返回最终的结果集。在这个过程中,是有一个深度分页问题的,就是分页的页数如果很深,那会导致查询的速度特别慢。
分布式系统中的深度分页问题
我们要理解为什么深度分页是有问题的,我们可以假设在一个有 5 个主分片的索引中搜索。 当我们请求结果的第一页(结果从 1 到 10 ),每一个分片产生前 10 的结果,并且返回给 协调节点,协调节点对 50 个结果排序得到全部结果的前 10 个。
现在假设我们请求第 1000 页--结果从 10001 到 10010 。所有都以相同的方式工作除了每个分片不得不产生前10010个结果以外。 然后协调节点对全部 50050 个结果排序最后丢弃掉这些结果中的 50040 个结果。
可以看到,在分布式系统中,对结果排序的成本随分页的深度成指数上升。这就是 web 搜索引擎对任何查询都不要返回超过 1000 个结果的原因。
五、总结
并行算法的用处很多,通过化整为零的方式,把一个很难处理的问题简化成无数个小问题来提升效率。这种思想在软件工程的用处特别大。包括我们的并发编程其实就是为了充分利用CPU的资源进行计算。而在大数据领域中的MapReduce,实际上就是一个非常优秀的并行计算框架。
我的微信公众号:架构真经(关注领取免费资源)
参考文章
- https://blog.csdn.net/qq_25800311/article/details/91352061
- https://blog.csdn.net/lsh_2013/article/details/48708401
转载:https://blog.csdn.net/m0_37609579/article/details/101175786