数据结构与算法笔记:高级篇 - 并行算法:如何利用并行处理提高算法的执行效率?

概述

时间复杂度是衡量算法执行效率的一种标准。但是,时间复杂度并不能跟性能划等号。在真是的软件开发中,即便在不降低时间复杂度的情况下,也可以通过一些优化手段,提升代码的执行效率。毕竟,对于实际的软件开发来说,即便是像 10%、20% 这样微小的性能提升,也是非常可观的。

算法的目的是为了提高代码的执行效率。那当算法无法再继续优化的情况下,我们该如何进一步提高执行效率呢? 本章就介绍一种非常简单,但是又非常好用的优化方法,那就是并行计算。本章,将通过几个例子,给你展示一下,如何借助并行计算的处理思想对算法进行改造?


并行排序

假设我们要给大小为 8GB 的数据进行排序,并且,我们机器的内存可以一次性容纳这么多数据。对于排序来说,最常用的就是时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) 的三种排序算法,归并排序、快速排序、堆排序。从理论上讲,这个排序问题,已经很难再从算法层面优化了。而利用并行处理的思想,我们可以很轻松地将这个给 8GB 数据排序问题的执行效率提高很多倍。具体的实现思路有下面两种。

第一种是对归并排序进行并行化处理
我们可以把这 8GB 的数据划分成 16 个小的数据集合,每个集合包含 500MB 的数据。我们用 16 个线程,并行地对这 16 个 500MB 的数据集合进行排序。这 16 个集合分别排序完成之后,我们再将这 16 个有序集合合并。

第二种是对快速排序并行化处理
我们通过扫描一遍数据,找到数据所处的范围区间。我们把这个区间从小到大划分成 16 个小区间。我们将 8GB 的数据划分到对应的区间中。针对这 16 个小区间的数据,我们启动 16 个线程,并行地进行排序。等到 16 个线程都执行结束之后,得到的数据就是有序数据了。

对比这两种处理思路,它们利用的都是分治的思想,对数据进行分片,然后并行处理。它们的区别在于,第一种处理思路是,先随便地对数据进行分配,排序之后再合并。第二种处理思路,先对数据按照大小划分区间,然后再排序,排完序就不需要再处理了。这个跟归并和快排的区别如出一辙。

这里我还要多说几句,如果要排序的数据规模不是 8GB,而是 1TB,那问题的重点就不是算法的执行效率了,而是数据的读取效率。因为 1TB 的数据肯定存储在磁盘中,无法一次性读取到内存中,这样在排序的过程中,就会有很频繁的数据的读取和写入。如何减少磁盘的 IO 操作,减少磁盘数据读取和写入的总量,就变成了重点。不过这个不是本章节的重点,你可以自行思考下。

并行查找

我们知道,散列表是一种非常适合快速查找的数据结构。

如果我们是给动态数据结构构建索引,在数据不断加入的时候,散列表的装载因子会越来越大。为了保证散列表的性能不下降,我们就需要对散列表进行扩容。对如此大的散列进行动态扩容,一方面比较耗时,另一方面比较消耗内存。比如,我们给一个 2GB 大小的散列表进行扩容,扩展到原来的 1.5 倍,也就是 3GB 大小。这个时候,实际存储在散列表中的数据只有不到 2GB,所以内存利用率只有 60%,有 1GB 的内存是空闲的。

实际上,我们可以将数据随机分割成 k 份(比如 16 份),每份中的数据只有原来的 1/K,然后我们针对这 k 个小数据集合分别构建散列表。这样,散列表的维护成本就变低了。当某个小散列表的装载因子过大时,我们可以单独对这个散列表进行扩容,而其他散列表不需要进行扩容。

还是刚才那个里子,假设现在只有 2GB 的数据,我们放到 16 个散列表中,每个散列表中的数据大约是 150MB。当某个散列表需要扩容的时候,我们只需要额外增加 150*0.75=75MB 的内存(假设还是扩容到原来的 1.5 倍)。无论从扩容的执行效率还是内存的利用率上,这种多个散列表的处理方法,都要比大散列表高效。

当我们要查找某个数据的时候,我们只需要通过 16 个线程,并行地在这 16 个散列表中查找数据。这样的查找性能,比起一个大散列表的做法,也并不会下降,反倒有可能提高。

当往散列表中添加数据的时候,我们可以选择将这个数据放入装载因子最小的那个散列表中,这样也有助于减少散列冲突。

并行字符串匹配

我们前面学过,在文字查找某个关键词这样一个功能,可以通过字符串匹配算法来实现。之前学过的字符串匹配算法有 KMP、BM、RK、BF 等。当在一个不是很长的文本中查找关键词的时候,这些字符串匹配算法中的任何一个,都可以表现的非常高效。但是,如果我们处理的是超级大的文本,那处理的时间可能就会变得很长,那有没有办法加快匹配速度呢?

我们可以把大文本,分割成 k 个小文本。假设 k 是 16,我们就启动 16 个线程,并行地在 16 个小文本中查找关键词,这样整个查找的性能就提高了 16 倍。16 倍效率的提升,从理论的角度来说并不多。但是,对于真实的软件开发来说,这显然是一个非常客观的优化。

不过,这里还有一个细节要处理,那就是原本包含在大文本中的关键词,被一分为二,分割到两个小文本中,这就会导致大文本中包含的这个关键词,但是在这 16 个小文本中查找不到它。实际上,这个问题也可以解决,我们只需要针对这种特殊情况,做一些特殊处理就可以了。

假设关键词的长度是 m。我们在每个小文本的结尾和开始各取 m 个字符串。前一个小文本的末尾 m 个字符和后一个小文本的开始 m 个字符,组成一个 2m 的字符串。我们再拿关键词,在这 2m 长度的字符串中再重新查找一遍,就可以不上刚才的漏洞了。

并行搜索

前面我们学习过几种搜索算法啊,它们分别是广度优先搜索、深度优先搜索、Dijkstra 最短路径算法、A*启发式搜索算法。对于广度优先搜索算法,我们也可以将其改造成并行算法。

广度优先搜索是一种逐层搜索的搜索策略。基于当前这一层顶点,我们可以启动多个线程,并行地搜索下一层的顶点。在代码实现方面,原来广度优先搜索算法的代码实现,是通过一个队列来记录已经比那里到但还没有扩展的顶点。现在,经过改造之后的并行广度优先搜索算法,我们需要利用两个队列来完成扩展点顶点的工作。

假设这两个队列分别为队列 A 和队列 B。多线程并行处理队列 A 中的顶点,并将其扩展顶点存储在队列 B 中。等队列 A 中的顶点都扩展完成之后,队列 A 被清空,我们再并行地扩展队列 B 中的顶点,并将其扩展出来的顶点存储在队列 A。这两个队列循环使用,就可以实现并行广度优先搜索算法了。

总结

上篇文章,我们通过实际软件开发中的 “索引” 这一技术点,回顾了之前学过的一些支持动态数据集合的数据结构。本章,又通过 “并行算法” 这个话题,回顾了之前学过的一些算法。

本章的内容比较简单,没有太复杂的知识点。我通过一些例子,比如并行排序、查找、搜索、字符串匹配,给你展示了并行处理的实现思路,也就是对数据进行分片,对没有依赖关系的任务,并行地执行。

并行计算是一个工程上的实现思路,尽管跟算法的关系不大,但是,在实际的软件开发中,它确实可以非常巧妙地提高程序的运行效率,是一种非常好的性能优化手段。

特别是,当要处理的数据规模达到一定程度之后,我们无法通过继续优化算法,来提供执行效率的时候,我们就需要再实现的思路上做文章,利用更多的硬件资源,来加快执行效率。所以,在很多超大规模数据处理中,并行处理的思想,应用非常广泛,比如 MapReduce 实际上就是一种并行计算框架。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/39023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Compose 十二:常用组件列表 上拉加载

列表 上拉加载 当前思路 判断 列表最后一个显示的条目 为 数据集合的长度-1 用来记录刷新状态 var refreshing by remember {mutableStateOf(false)}数据集合 val list remember{List(10){"条目》》${it}"}.toMutableStateList()}用来记录列表当前状态及状态变化…

行业分析---造车新势力之极氪汽车

1 前言 在之前的博客中,笔者撰写了多篇行业类分析的文章(科技新能源): 《行业分析---我眼中的Apple Inc.》 《行业分析---马斯克的Tesla》 《行业分析---造车新势力之蔚来汽车》 《行业分析---造车新势力之小鹏汽车》 《行业分析-…

心跳机制简介

心跳机制 心跳机制(Heartbeat Mechanism)是一种用于监控和维护计算机系统、网络和分布式系统中各个节点之间连接状态的技术。它通过周期性地发送信号(即“心跳”)来确认系统组件之间的活跃性和可用性。如果某个节点没有在预期时间…

fastapi swagger js css 国内访问慢问题解决

fastapi swagger js css 国内访问慢问题解决 直接修改fastapi包中静态资源地址为如下地址 swagger_js_url: str "https://cdn.bootcdn.net/ajax/libs/swagger-ui/3.9.3/swagger-ui-bundle.js", swagger_css_url: str "https://cdn.bootcdn.net/ajax/libs/sw…

1971计算机毕业设计asp.net游乐园信息管理系统 VS开发access数据库web结构c#编程计算机网页源码项目

一、源码特点 asp.net游乐园信息管理系统 是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 asp.net游乐园管理系统 二、功能介绍 前台功能: 1)系统首页浏览 2)园区通知浏…

leetcode-19-回溯-组合问题(剪枝、去重)

引自代码随想录 一、[77]组合 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 示例: 输入: n 4, k 2 输出: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4]] 1、大致逻辑 k为树的深度,到叶子节点的路径即为一个结果 开始索引保证不…

【计算机网络】网络层(作业)

【一】 1、某主机的 IP 地址为 166.199.99.96/19。若该主机向其所在网络发送广播 IP 数据报, 则目的地址可以是(D)。 A. 166.199.99.255B. 166.199.96.255C. 166.199.96.0D. 166.199.127.255 解析: 166.199.99.96/19166.199.0…

深入解读OkHttp3中的Dispatcher

OkHttp3是一个非常流行的HTTP客户端,用于与服务器通信。Dispatcher是OkHttp3中的一个关键组件,负责管理和调度请求。在这篇博客中,我们将深入探讨Dispatcher的工作原理、相关类的关系以及其实现细节。 什么是Dispatcher?&#x1…

STM32 看门狗 HAL

由时钟图可以看出看门狗采用的是内部低速时钟,频率为40KHz 打开看门狗,采用32分频,计数1250。 结合设置的分频系数和重载计数值,我们可以计算出看门狗的定时时间: 32*1250/40kHz 1s 主函数中喂狗就行 HAL_IWDG_Ref…

车载资料分享中:硬件在环、canoe、UDS诊断、OTA升级、TBOX测试

每日直播时间: 周一到周五:20:00-23:00 周六与周日:9:00-17:00 直播内容:(车厂一比一测试) HIL(硬件在环)测试、UDS功能诊断、UDS自动…

Java集合整理笔记

目录 1.集合基础概念 1.1 集合 1.2 单例集合 1.2.1 List系列 1、ArrayList 2、LinkedList 3、Voctor​编辑 1.2.2 Set系列 1、HashSet 集合 2、LinkedHashSet 集合 3、TreeSet集合 1.3 双例集合 1.3.1 HashMap 1.3.2 LinkedHashMap 1.3.3 TreeMap 1.4 快速失败…

小抄 20240630

1 大学和电视剧里演的大学,是两回事,不要带着电视剧的滤镜去看大学。 你的大学室友不一定能成为朋友,你的教官不一定有你情绪稳定,你的恋爱可能是杀猪盘,你的学长学姐给你领路可能只是为了高溢价卖你垃圾东西。 上大…

华为机试HJ2计算某字符出现次数

华为机试HJ2计算某字符出现次数 题目: 计算字符串中的某个字符出现的次数,不区分大小写。 想法: 将输入的字符串和要查询的字符变为小写,遍历整个字符串统计要查的字符个数。 input_str input().lower() check_str input()…

一篇搞懂!LinuxCentos中部署KVM虚拟化平台(文字+图片)

🏡作者主页:点击! 👨‍💻Linux高级管理专栏:点击! ⏰️创作时间:2024年6月28日15点11分 🀄️文章质量:94分 目录 ————前言———— KVM的优点 KVM…

【embedding 神经网络】神经网络算法 —— Embedding(嵌入)!!

文章目录 前言 1、Embedding的本质 (1)机器学习中的Embedding (2)NLP中的Embedding 2、Embedding的原理 (1)Image Embedding(图像嵌入) (2)Word Embed…

geoserver添加 GeoTiff

GeoTIFF 是一种广泛使用的地理空间栅格数据格式。它由一个包含数据和地理参考信息的文件组成。本节提供添加和发布 GeoTIFF 文件的说明。 打开 Web 浏览器并导航到 GeoServer欢迎页面。 从界面中选择添加商店。 从可用的栅格数据源集合中选择GeoTIFF - 带有地理信息的标记图…

解决卡顿发热,超帧技术焕发中重载游戏动力

近几年,中国手游市场规模不断扩大,开发者通过在画面、玩法等方面的持续创新和打磨,推出更加精品化的产品。然而愈发精美的画质和复杂的玩法,也给硬件带来超高的负载,导致玩家在游戏过程中,频繁出现掉帧卡顿…

elementUI 年份范围选择器实现

elementUI 不支持年份范围的选择器,依照下面的文章进行修改和完善 el-year-picker; element日期选择范围、选择年份范围_elemet 两个日期 选择的年份范围必须在三年之内-CSDN博客 el-year-picker 组件: 依赖包:moment 属性&…

算法训练营day06 哈希表(统计数,去重,降低时间复杂度)

💡 解题思路 📝 确定输入与输出🔍 分析复杂度🔨 复杂题目拆分 :严谨且完整 地拆分为更小的子问题(哈希表的使用场景)–(多总结)💭 选择处理逻辑:…

LLM-Transformer:经典与前沿方法详解

LLM-Transformer:经典与前沿方法详解 前言 大规模语言模型(LLM)是当前自然语言处理(NLP)领域的核心技术,而Transformer架构作为LLM的基础,极大地推动了这一领域的发展。本文将详细介绍LLM-Tra…