深入MapReduce——引入
引入
前面我们已经深入了HDFS的设计与实现,对于分布式系统也有了不错的理解。
但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值,一定是需要从数据中挖掘出价值才行,这就需要我们拥有海量数据的计算处理能力。
下面我们还是老样子,来数据一下要实现海量计算处理能力,有些什么核心痛点
大数据计算核心痛点
量级大
在稍微大一点的互联网企业,需要计算处理的数据量都开始以PB计了。而传统的计算处理模型中,一个程序所能调度的网络带宽通常在数百MB、内存容量通常就几十GB 、磁盘大小通常也就数TB,根本解决不了这么大量级的数据计算需求。(什么?我打宿傩?)
易用差
虽然在04年已经有了分布式计算,但是那个时候的分布式计算都是专用的系统,只能专门处理某一类计算,比如进行大规模数据的排序。这样的系统没办法复用到其他的大数据计算场景,每一种应用都需要开发与维护专门的系统。很难让让没有分布式系统知识和经验的人,可以快速简便地去利用分布式计算处理海量数据。
门槛高
而且因为分布式系统中遇到故障和失败,是一个很常见的问题,传统的分布式程序设计(如MPI)非常复杂,用户需要关注的细节非常多,比如数据分片、数据传输、节点间通信等,因而设计分布式程序的门槛非常高。
容错差
在分布式环境下,随着集群规模的增加,集群中的故障率会显著增加,进而导致任务失败和数据丢失的可能性增加。
这里的“故障”主要指磁盘损坏、机器宕机、节点间通信失败等硬件故障和坏数据,以及用户程序bug产生的软件故障等。
Hadoop MapReduce设计
针对这些痛点,MapReduce的核心设计目标:在保障扩展性和容错性的前提下,提升海量数据计算处理的易用性!
而它的实现的核心思路也很简答,就是通过开发统一通用的编程模型,并构建一个抽象和高层的编程接口和框架,屏蔽分布式领域的复杂问题,让开发者能够专注于分析程序的业务逻辑。
模型本质就是对现实世界中某种事物或现象的一种概括、抽象的表示。 比如函数是输入和输出之间关系的抽象;数学公式是对物理与数学规律的抽象;软件架构图是软件工程师对软件系统的抽象。
通过前面深入HDFS的篇章,我们知道,从本质上来看,HDFS就是通过抽象、封装的思想,把成百上千台服务器、成千上万块硬盘的硬件做了一个封装,屏蔽了底层复杂实现,让使用者可以把它当成一块硬盘来使用,这极大的降低了它的使用门槛。
其实无论是什么领域,学会去抽象总结,才能把握事物的内在规律,而不是被纷繁复杂的事物表象所迷惑,才能更进一步深刻地认识这个世界!
为了让大家先对MapReduce这个通用模型有个初步的概念,我举个通俗的例子——假设我们有一大堆杂乱无序的相同品牌的扑克牌,要快速把它们梳理出有多少副完整的扑克牌,就可以分几个组,一组人分别梳理一堆牌,把相同的牌放到一个位置,然后下一组人基于这些牌去计数不同的牌有多少张,最后汇总起来,就能知道可以组成多少副完整的扑克牌了。
下面我们看看Hadoop MapReduce的设计与落地的总体思路。
参考思想:Unix设计哲学&Unix下的Bash和管道
MapReduce的设计哲学和Unix是一样的,叫做 “Do one thing, and do it well”,也就是每个模块只做一件事情,但是把这件事情彻底做好。
而MapReduce的计算流程设计思想,也是参考了Unix系统中,利用一个个命令,通过管道把数据处理流程串接起来处理的模式。
参考设计:Lisp类函数式编程
其实MapReduce编程模型并不是Hadoop原创,甚至也不是Google原创,而是借鉴了Lisp(python、scala)这类函数式编程语言的思想。
熟悉Java Stream API的都对这种编程模式并不陌生,它实际上就是map、groupingBy、reduce之类的操作,这种编程模型分离了程序的业务逻辑和控制逻辑,使得程序在大规模的分布式环境下运行成为了可能。
另外,尽管MapReduce编程模型非常简单,现实中的大多数任务却都可以用这种编程模型来表达,这在函数式编程语言中已经得到了证明,它为MapReduce后来广泛地流行奠定了基础。
参考论文:MapReduce: Simplified data processing on large cluster
Google在2004年发布的这篇论文也是大数据的三驾马车之一!
该论文主要包含下面内容:
-
MapReduce的计算模型和应用场景;
-
MapReduce实际是如何实现的,使得开发者无需关心分布式的存在;
-
如何逐步迭代优化MapReduce的性能。
这里就不单独开一篇文章介绍了,下面我们把论文里面的核心内容梳理一下。
需求场景
第一种,是对所有的数据,都只需要单条数据就能完成处理。
比如,有很多网页的内容,要从里面提取出来每一个网页的标题。这样的计算可以完全并行化。
第二种,是需要汇总多条数据才能完成计算。
比如,要统计日志里面某个URL被访问了多少次,只需要简单累加就可以了。
比如统计某个URL下面的唯一用户数,就需要将所有相同URL的数据,搬运到同一个计算节点上进行处理。不过,在搬运之后,不同的URL还是可以放到不同的节点进行处理的。
第三种,自然是一、二两种情况的组合了。
比如,先从网页数据里面,提取出网页的URL和标题,然后根据标题里面的关键字,统计特定关键字出现在多少个不同的URL里面,这就需要同时采用一二这两种情况的操作。
当然还有更复杂的数据操作,但是这些动作也都可以抽象成前面的两个动作的组合。因为无非,要处理的数据要么是完全独立的,要么需要多条数据之间的依赖。
计算模型
前面需求场景的
第一种动作,就是 MapReduce 里面的 Map
Map 函数,顾名思义就是一个映射函数,它会接受一个 key-value 对,然后把这个 key-value 对转换成0到多个新的 key-value 对并输出出去。
第二种动作,就是 MapReduce 里面的 Reduce
Reduce 函数,则是一个化简函数,它接受一个 Key,以及这个 Key 下的一组 Value,然后化简成一组新的值 Value 输出出去。
Map 函数的输出结果,会被整个 MapReduce 程序接手,进行 shuffle 操作。也就是数据搬运的过程。
shuffle 会把 Map 函数输出的所有相同的 Key 的 Value 整合到一个列表中,给到 Reduce 函数。并且给到 Reduce 函数的 Key,在每个 Reduce 里,都是按照 Key 排好序的。
它们就构建了 MapReduce 的计算模型
注意:
shuffle 过程的排序操作,并不是 MapReduce 框架本身的核心需求,而是为了技术上实现方便。因为我们要把相同 Key 的数据放到一起处理,而通过一个 HashMap 把所有的数据放在内存里,又不一定放得下。那么利用硬盘进行外部排序是一个最简单的,没有内存大小依赖的,对数据根据 Key 进行分组的解决办法。
MapReduce 计算模型的设计,其实就是典型的模版方法模式(Template Method Pattern)。
与其说它是一个分布式数据处理系统,不如说是分布式数据处理框架。
因为 MapReduce 框架已经设定好了整个数据处理的流程,用户只需要实现 Map 和 Reduce 这两个接口函数,就能完成海量的数据处理。
应用场景
论文里列了以下六个应用场景:
-
分布式 grep ;
-
统计 URL 的访问频次;
-
反转网页-链接图;
-
分域名的词向量;
-
生成倒排索引;
-
分布式排序。
实现挑战
要想让写 Map 和 Reduce 函数的人不需要关心“分布式”的存在,那么 MapReduce 框架本身就需要解决好三个很重要的问题:
-
第一个,自然是如何做好各个服务器节点之间的“协同”,以及解决出现各种软硬件问题后的“容错”这两部分的设计。
-
第二个,性能问题。MapReduce 框架非常容易遇到网络性能瓶颈。尽量充分利用 MapReduce 集群的计算能力,并让整个集群的性能可以随硬件的增加接近于线性增长,可以说是非常大的一个挑战。
-
最后一个,易用性问题。Map 函数和 Reduce 函数最终还是运行在多个不同的机器上的,并且在 Map 和 Reduce 函数中还会遇到各种千奇百怪的数据。当我们的程序在遭遇到奇怪的数据出错的时候,我们需要有办法来进行 debug。
MapReduce 的协同
MapReduce的集群,通常就是分布式存储系统GFS的集群。
在这个集群里,本身会有一个调度系统(Scheduler)。
当我们要运行一个MapReduce任务的时候,其实就是把整个MapReduce的任务提交给这个调度系统,让这个调度系统来分配和安排 Map 函数和 Reduce 函数,以及后面会提到的 master 在不同的硬件上运行。
在MapReduce任务提交了之后,整个MapReduce任务就会按照这样的顺序来执行:
-
第一步,由于写好的MapReduce程序,已经指定了输入路径。所以MapReduce会先找到GFS 上的对应路径,然后把对应路径下的所有数据进行分片(Split)。每个分片的大小通常是 64MB,这个尺寸也是GFS里面一个块(Block)的大小。接着,MapReduce 会在整个集群上,启动很多个MapReduce程序的复刻(fork)进程。
-
第二步,在这些进程中,有一个和其他不同的特殊进程,就是一个master进程,剩下的都是worker进程。然后,会有M个map的任务以及R个 reduce 的任务,分配给这些worker进程去进行处理。这里的master进程,是负责找到空闲的(idle)worker进程,然后再把map任务或者reduce任务,分配给worker进程去处理。
这里需要注意一点,并不是每一个map和reduce任务,都会单独建立一个新的worker 进程来执行。而是master进程会把map和reduce任务分配给有限的worker,因为一个worker通常可以顺序地执行多个map 和reduce 的任务。
-
第三步,被分配到map任务的worker会读取某一个分片,分片里的数据会变成一个个key-value对喂给map任务,然后等Map函数计算完后,会生成的新的key-value对缓冲在内存里。
-
第四步,这些缓冲了的key-value对,会定期地写到map任务所在机器的本地硬盘上。
并且按照一个分区函数(partitioning function),把输出的数据分成R个不同的区域。
而这些本地文件的位置,会被worker传回给到master节点,再由master节点将这些地址转发给reduce任务所在的worker 那里。
-
第五步,运行reduce任务的worker,在收到master的通知之后,会通过RPC(远程过程调用)来从map任务所在机器的本地磁盘上,抓取数据。当reduce任务的worker 获取到所有的中间文件之后,它就会将中间文件根据Key进行排序。这样,所有相同Key的Value 的数据会被放到一起,也就是完成了混洗(Shuffle)的过程。
-
第六步,reduce会对排序后的数据执行实际的Reduce函数,并把reduce的结果输出到当前这个reduce分片的最终输出文件里。
-
第七步,当所有的map任务和reduce任务执行完成之后,master会唤醒启动MapReduce任务的用户程序,然后回到用户程序里,往下执行MapReduce任务提交之后的代码逻辑。
整个MapReduce的执行过程,也是一个典型的 Master-Slave 的分布式系统。map和 reduce所在的worker之间并不会直接通信,它们都只和master通信。另外,像是map 的输出数据在哪里这样的信息,也是告诉master,让master转达给reduce 所在的 worker。reduce从map里获取数据,也是直接拿到数据所在的地址去抓取,而不是让reduce通过RPC,调用map所在的worker去获取数据。
MapReduce 的容错(Fault Tolerance)
MapReduce的容错机制非常简单,可以简单地用两个关键词来描述,就是重新运行和写Checkpoints。
worker 节点的失效(Master Failure)
对于Worker 节点的失效,MapReduce框架解决问题的方式非常简单。就是换一台服务器重新运行这个Worker节点被分配到的所有任务。master节点会定时地去ping每一个worker 节点,一旦worker节点没有响应,就会认为这个节点失效了。于是,master会重新在另一台服务器上,启动一个worker进程,并且在新的worker进程所在的节点上,重新运行所有失效节点上被分配到的任务。而无论失效节点上,之前的map和 reduce任务是否执行成功,这些任务都会重新运行。因为在节点ping不通的情况下,很难保障它的本地硬盘还能正常访问。
master 节点的失效(Worker Failure)
对于 master节点的失效,直接就任由master节点失败了,也就是整个MapReduce任务失败了。而对于开发者来说,解决这个问题的办法也很简单,就是再次提交一下任务去重试。
因为master进程在整个任务中只有一个,它会失效的可能性很小。而MapReduce的任务也是一个用户离线数据处理的任务,并不是一个实时在线的服务,失败重来通常也没有什么影响,只是晚一点拿到数据结果罢了。
虽然在论文发表的时候,谷歌并没有实现对于master的失效自动恢复机制,但他们也给出了一个很简单的解决方案,那就是让master定时把它里面存放的信息,作为一个个的Checkpoint写入到硬盘中去。
针对这个其实可以把这个Checkpoint直接写到GFS里,然后让调度系统监控master。这样一旦master失效,就可以启动一个新的master,来读取Checkpoints 数据,然后就可以恢复任务,并继续执行了,而不需要重新运行整个任务。
对错误数据视而不见
worker 和 master 的节点失效,以及对应的恢复机制,通常都是来自于硬件问题。但是在海量数据处理的情况下,比如在TB乃至PB级别的数据下,还会经常遇到“脏数据”的问题。
这些数据,可能是日志采集的时候就出错了,也可能是一个非常罕见的边界情况(edge-case),我们的Map和Reduce 函数正好处理不了。甚至有可能,只是简单的硬盘硬件的问题带来的错误数据。
那么,对于这些异常数据,我们固然可以不断debug,一一修正。但是这么做,大多数时候都是划不来的,因为很可能为了一条数据记录,由于Map函数处理不了,你就要重新扫描几TB的数据。
所以,MapReduce不仅为节点故障提供了容错机制,对于这些极少数的数据异常带来的问题,也提供了一个容错机制。MapReduce会记录Map或者Reduce函数,运行出错的具体数据的行号,如果同样行号的数据执行重试还是出错,它就会跳过这一行的数据。如果这样的数据行数在总体数据中的比例很小,那么整个MapReduce程序会忽视这些错误,仍然执行完成。毕竟,一个URL被访问了1万次还是9999次,对于搜素引擎的排序结果不会有什么影响。
MapReduce 的性能优化
MapReduce集群里的硬件配置方面的最大瓶颈,自然和 GFS 也一样——网络带宽。
把程序搬到数据那儿去
既然网络带宽是瓶颈,那么优化的办法自然就是尽可能减少需要通过网络传输的数据。在MapReduce这个框架下,就是在分配map任务的时候,根据需要读取的数据在哪里进行分配。由于GFS是知道每一个Block 的数据是在哪台服务器上的。而MapReduce,会找到同样服务器上的worker,来分配对应的map 任务。如果那台服务器上没有,那么它就会找离这台服务器最近的、有worker 的服务器,来分配对应的任务。
除此之外,由于MapReduce程序的代码往往很小,可能只有几百KB或者几MB,但是每个map需要读取的一个分片的数据是64MB大小。这样,我们通过把要执行的MapReduce程序,复制到数据所在的服务器上,就不用多花那10倍乃至100倍的网络传输量了。
通过Combiner减少网络数据传输
除了Map函数需要读取输入的分片数据之外,Reduce所在的worker去抓取中间数据,一样也需要通过网络。那么要在这里减少网络传输,最简单的办法,就是尽可能让中间数据的数据量小一些。
在MapReduce的框架里,MapReduce允许开发者自己定义一个Combiner 函数。这个Combiner函数,会对在同一个服务器上所有map 输出的结果运行一次,然后进行数据合并。实际上,不仅是同一个Map函数的输出可以合并,同一台服务器上多个Map的输出,我们都可以合并。反正它们都在一台机器上,合并只需要本地的硬盘读写和CPU,并不需要我们最紧缺的网络资源。以域名的访问次数为例,它的数据分布一定有很强的头部效应,少量20%的域名可能占了80%的访问记录。这样一合并,我们要传输的数据至少可以减少60%。如果考虑一台 16 核的服务器,有16个map的worker运行,应该还能再减少80%以上。这样,通过一个中间的Combiner,我们要传输的数据一下子就下降了两个数量级,大大缓解了网络传输的压力。
注意:不是所有场景都能预聚合处理的,比如求中位数。
MapReduce 的 debug 信息
虽然我们一直说,我们希望MapReduce让开发者意识不到分布式的存在。但是归根到底,map和reduce的任务都是在分布式集群上运行的,这个就给我们对程序debug 带来了很大的挑战。无论是通过debugger做单步调试,还是打印出日志来看程序执行的情况,都不太可行。
所以,MapReduce也为开发者贴心地提供了三个办法来解决这个问题:
-
第一个,是提供一个单机运行的MapReduce的库,这个库在接收到MapReduce任务之后,会在本地执行完成map和reduce的任务。这样,你就可以通过拿一点小数据,在本地调试你的MapReduce任务了,无论是debugger还是打日志,都行得通。
-
第二个,是在master 里面内嵌了一个HTTP服务器,然后把master的各种状态展示出来给开发者看到。这样一来,你就可以看到有多少个任务执行完了,有多少任务还在执行过程中,它处理了多少输入数据,有多少中间数据,有多少输出的结果数据,以及任务完成的百分比等等。同样的,里面还有每一个任务的日志信息。
另外通过这个HTTP 服务器,你还可以看到具体是哪一个worker里的任务失败了,对应的错误日志是什么。这样,你就可以快速在线上定位你的程序出了什么错,是在哪台服务器上。
-
最后一个,是MapReduce框架里提供了一个计数器(counter)的机制。作为开发者,你可以自己定义几个计数器,然后在Map 和Reduce的函数里去调用这个计数器进行自增。所有 map 和reduce的计数器都会汇总到master节点上,通过上面的HTTP服务器里展现出来。
比如,你就可以利用这个计数器,去统计有多少输入日志的格式和预期的不一样。如果比例太高,那么多半你的程序就有Bug,没有兼容所有合法的日志。
遗憾与缺陷
尽管MapReduce框架已经作出了很多努力,但是今天来看,整个计算框架的缺陷还是不少的。
主要的缺陷有两个:
-
第一个是还没有100%做到让用户意识不到“分布式”的存在,无论是Combiner 还是Partitioner,都是让开发者意识到,它面对的还是分布式的数据和分布式的程序。
-
第二个是性能仍然不太理想,这体现在两个方面:
-
一个是每个任务都有比较大的overhead,都需要预先把程序复制到各个 worker 节点,然后启动进程;
-
另一个是所有的中间数据都要读写多次硬盘。map 的输出结果要写到硬盘上,reduce抓取数据排序合并之后,也要先写到本地硬盘上再进行读取,所以快不起来。
-
Hadoop MapReduce核心设计
Hadoop MapReduce 参考了上面的相关内容,其设计和落地在企业落地后,也是有不断优化迭代的。
和MapReduce的论文不太一样。在Hadoop1.0实现里,每一个MapReduce的任务并没有一个独立的master进程,而是直接让调度系统承担了所有的worker 的master 的角色,这就是Hadoop1.0里的 JobTracker。在Hadoop1.0里,MapReduce论文里面的worker就是TaskTracker,用来执行map 和 reduce的任务。而分配任务,以及和TaskTracker沟通任务的执行情况,都由单一的JobTracker 来负责。
这个设计,也导致了只要服务器数量一多,JobTracker的负载就会很重。所以早年间,单个Hadoop 集群能够承载的服务器上限,被卡在了4000台。而且JobTracker也成为了整个Hadoop 系统很脆弱的“单点”。
在Hadoop 2.0,Hadoop社区把JobTracker的角色,拆分成了进行任务调度的Resource Mananger,以及监控单个MapReduce任务执行的Application Master,回到了和MapReduce论文相同的架构。
MRv1
第一代MapReduce计算框架,由两部分组成:编程模型(programming model)和运行时环境(runtime environment)。
基本编程模型是将问题抽象成Map和Reduce两个阶段。
-
Map阶段将输入数据解析成 key/value,迭代调用 map() 函数处理后,再以 key/value 的形式输出到本地目录;
-
Reduce 阶段则将 key 相同的 value 进行 reduce 处理,并将最终结果写到 HDFS 上。
运行时环境由两类服务组成:JobTracker 和 TaskTracker。
-
JobTracker 负责资源管理和所有作业的控制
-
TaskTracker 负责接收来自JobTracker的命令并执行它
YARN/MRv2
针对MRv1中的MapReduce在扩展性和多框架支持方面的不足,提出了全新的资源管理框架YARN(Yet Another Resource Negotiator)。
将JobTracker中的资源管理和作业控制功能分开,分别由两个不同进程ResourceManager和ApplicationMaster实现。
-
ResourceManager负责所有应用程序的资源分配
-
ApplicationMaster仅负责管理一个应用程序
总结
今天我们梳理了MapReduce的设计与实现的思路,后面我们深入源码去看看MapReduce有哪些有意思的东西。
相关文章:
深入MapReduce——引入
引入 前面我们已经深入了HDFS的设计与实现,对于分布式系统也有了不错的理解。 但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值,一定是需要从数据中挖掘出价值才行,这就需要我们拥有海量数据的计算处理能力。 下面我们还是…...
Formality:不可读(unread)的概念
相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482https://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 在Formality中有时会遇到不可读(unread)这个概念,本文就将对此…...
leetcode刷题记录(八十一)——236. 二叉树的最近公共祖先
(一)问题描述 236. 二叉树的最近公共祖先 - 力扣(LeetCode)236. 二叉树的最近公共祖先 - 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科 [https://baike.baidu.com/item/%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B…...
C++:将字符数组rkpryyrag,每个字母转换为其前面第13个字母后输出,如果超过a则从z再继续接着数。例如:b前面第1个字母是a。a前面第3个字母是x。
代码如下: #include <iostream> #include <string> using namespace std;int main(){string str "rkpryyrag";for (int i 0; i < str.length(); i){if (str[i] > a && str[i] < z){if (str[i] - a < 13){cout <<…...
特征选择(机器学习)
目录 1. 为什么需要特征选择2. 常见的特征选择方法2.1 过滤式(Filter Methods)小示例(用 Python 伪代码表达): 2.2 包裹式(Wrapper Methods)小示例(RFE 伪代码示例)&…...
基于微信小程序的个人健康管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...
Windows系统提示RunDLL PcaWallpaperAppDetect错误修复方法
最近,Win11 24H2预览版和Win10 LTSC 2025功能更新偶尔会触发RunDLL错误弹窗 具体表现为 //英文提示 Error in C:\WINDOWS\system32\PcaSvc.dll Missing entry: PcaWallpaperAppDetect//中文提示 C:\WINDOWS\system32\PcaSvc.dll出错 丢失条目:PcaWallpaperAppDe…...
文件上传漏洞详解
第一关(JS绕过) 1.1使用bp进行绕过 先将要上传的php文件的后缀改为png,然后在上传时抓包,将png后缀再改为php,发包,此时上传成功 1.2使用js进行绕过 打开浏览器的检查,将其中的checkFile函数…...
mysql的mvcc
快速搞懂mvcc 全称 multi-version concurrency control 多版本并发控制。自动开启事务undo log读视图(read_view)结果过滤mvcc只在读已提交和可重复读隔离级别下运作读已提交隔离级别下,可重复读隔离级别下,总的来说mvcc是为了提高数据库并发性能而设计的…...
漏洞情报:为什么、要什么和怎么做
漏洞一直是网络攻防的焦点所在,因为漏洞直接或间接影响安全性的核心方面——权限。攻击者挖掘和利用漏洞,获取非授权的权限;防御方定位和消除漏洞,监测和阻断漏洞的利用,使攻击者无法利用漏洞达到其目的。漏洞信息本质…...
kotlin的协程的基础概念
Kotlin的协程是一种用于简化异步编程的强大工具。 理解协程的基础概念可以帮助开发者有效地利用其能力。 以下是Kotlin协程的一些关键基础概念: 协程(Coroutines) : 协程是一种用于处理并发任务的编程模型,它可以在单…...
C语言教程——动态内存管理(2)
文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据 总结 前言 我们之前学了动态内存管理分配函数,也是熟悉了动态内存分配函数,基于动态内存分配我把之前的通讯录做了修改,上传到了gitee上,这篇文章接着…...
LeetCode刷题 -- 45.跳跃游戏 II
题目 C代码 int jump(int* nums, int numsSize) {int i 0;int j 0;int last_i 0;int last_can 0;int max_i 0;int max_can 0;int min_jump 0;if (numsSize < 2) {//注意点1:数组小于两个的时候,只需要跳转0次;goto end;}// 注意点…...
谈谈RTMP|RTSP播放器视频view垂直|水平反转和旋转设计
技术背景 我们在做RTMP|RTSP播放器的时候,有这样的技术诉求,有的摄像头出来的数据是有角度偏差的,比如“装倒了”,或者,图像存在上下或者左右反转,这时候,就需要播放器能做响应的处理ÿ…...
vulnhub靶场【kioptrix-1靶机】
前言 靶机:kioptrix-1,IP地址为192.168.1.104 攻击:kali,IP地址为192.168.1.16 都采用虚拟机,网卡为桥接模式 文章中涉及的靶机,来源于vulnhub官网,想要下载,可自行访问官网下载&…...
PyQt5之QCalendarWidget
十八、QCalendarWidget 1.描述 提供了一个基于每月日历控件,允许用户选择一个日期。 继承自QWidget 2.功能作用 (1) 构造函数 QCalendarWidget(parent: QWidget None)(2) 日期范围 setMinimumDate(QDate date) minimumDate() -> QDate setMaximumDate(QD…...
【Qt】窗口
窗口 菜单栏 QMenuBar给菜单设置快捷键添加子菜单添加分割线设置图标 工具栏 QToolBar状态栏 QStatusBar浮动窗口 QDockWidget对话框自定义对话框通过代码方式通过图形化方式 模态对话框 Qt 内置对话框消息对话框 QMessageBox颜色对话框 QColorDialog文件对话框 QFileDialog字体…...
初阶5 排序
本章重点 排序的概念常见排序的算法思想和实现排序算法的复杂度以及稳定性分析 1.排序的概念 排序: 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性: 假定在待排序的记录序列中࿰…...
备赛蓝桥杯之第十五届职业院校组省赛第二题:分享点滴
提示:本篇文章仅仅是作者自己目前在备赛蓝桥杯中,自己学习与刷题的学习笔记,写的不好,欢迎大家批评与建议 由于个别题目代码量与题目量偏大,请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题࿰…...
qml ColumnLayout详解
1、概述 ColumnLayout 是 QML 中用于在垂直方向上排列子元素的一种布局管理器。它继承自 Item 并提供了简单的布局机制,使得子元素能够按照从上到下的顺序自动排列。ColumnLayout 通常用于创建具有垂直层次结构的用户界面。 2、重要属性 layoutDirection 类型&…...
Qt 5.14.2 学习记录 —— 십팔 对话框
文章目录 1、Qt对话框2、自定义对话框1、代码方式2、图形化方式 3、模态对话框4、QMessageBox5、QColorDialog6、QFileDialog7、QFontDialog8、QInputDialog 1、Qt对话框 Qt的对话框用QDialog类来表示,可以自定义一些类来实现自定义对话框,但需要继承自…...
AI 编程工具—Cursor进阶使用 Rules for AI
AI 编程工具—Cursor进阶使用 Rules for AI 这里配置是给所有的会话和内嵌模式的,你可以理解为是一个全局的配置 下面的代码是之前Cursor 给我们生成的,下面我们开始配置Rules ,来让Cursor生成的代码更加符合我们的编程习惯 def quick_sort(arr):"""使用快…...
SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例
SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例 关键接口类: CronTaskRegistrar SchedulingRunnable . 添加定时任务注册类,用来增加、删除定时任务 impo…...
FPGA中场战事
2023年10月3日,英特尔宣布由桑德拉里维拉(Sandra Rivera)担任“分拆”后独立运营的可编程事业部首席执行官。 从数据中心和人工智能(DCAI)部门总经理,转身为执掌该业务的CEO,对她取得像AMD掌门人苏姿丰博士类似的成功,无疑抱以厚望。 十年前,英特尔花费167亿美元真金白银…...
_CLASSDEF在C++中的用法详解及示例
_CLASSDEF在C++中的用法详解及示例 _CLASSDEF的定义与使用示例说明代码解析总结在C++编程中,宏(Macro)是一种预处理指令,它允许程序员在编译之前对代码进行文本替换。_CLASSDEF是一个自定义的宏,它提供了一种便捷的方式来定义类及其相关类型。本文将详细介绍_CLASSDEF在C+…...
缓存-Redis-数据结构-redis哪些数据结构是跳表实现的?
在 Redis 中,跳表(Skip List) 被用于实现 有序集合(Sorted Set) 数据结构。以下是对此实现的详细解释: Redis中的有序集合(Sorted Set) 有序集合(Sorted Set࿰…...
K8S中Service详解(二)
Service类型 Service的资源清单文件: --- kind: Service # 资源类型 apiVersion: v1 # 资源版本 metadata: # 元数据name: service # 资源名称namespace: dev # 命名空间 spec: # 描述selector: # 标签选择器,用于确定当前service代理哪些podapp: ngin…...
鸿蒙模块概念和应用启动相关类(HAP、HAR、HSP、AbilityStage、UIAbility、WindowStage、window)
目录 鸿蒙模块概念 HAP entry feature har shared 使用场景 HAP、HAR、HSP介绍 HAP、HAR、HSP开发 应用的启动 AbilityStage UIAbility WindowStage Window 拉起应用到显示到前台流程 鸿蒙模块概念 HAP hap包是手机安装的最小单元,1个app包含一个或…...
【EXCEL_VBA_实战】多工作薄合并深入理解
工作背景:多个工作薄存在冲突的名称,需快速合并 困难点:工作表移动复制时,若有冲突的名称,会不断弹出对话框待人工确认 思路:利用代码确认弹出的对话框 关键代码:Application.DisplayAlerts …...
Maven的下载安装配置
maven的下载安装配置 maven是什么 Maven 是一个用于 Java 平台的 自动化构建工具,由 Apache 组织提供。它不仅可以用作包管理,还支持项目的开发、打包、测试及部署等一系列行为 Maven的核心功能 项目构建生命周期管理:Maven定义了项目构建…...
网络打印机的搜索与连接(一)
介绍 网络打印机就是可以通过网络连接上的打印机,这类打印机分2种:自身具有互联网接入功能可以分配IP的打印机我们称为网络打印机、另外一种就是被某台电脑连接上去后通过共享的方式共享到网络里面的我们称为共享打印机。现在还有一种可以通过互联网连接…...
高并发压力测试
高并发压力测试 CountDownLatch就是JUC包下的一个工具,整个工具最核心的功能就是计数器。 需要一个并发安全的计数器来操作。CountDownLatch就可以实现。 给CountDownLatch设置一个数值。 每个业务处理完毕之后,执行一次countDown方法,指…...
Python中采用.add_subplot绘制子图的方法简要举例介绍
Python中采用.add_subplot绘制子图的方法简要举例介绍 目录 Python中采用.add_subplot绘制子图的方法简要举例介绍一、Python中绘制子图的方法1.1 add_subplot函数1.2 基本语法(1)add_subplot的核心语法(2)add_subplot在中编程中的…...
ipad和macbook同步zotero文献附件失败的解决办法
背景:我所有的文献及其附件pdf都是在台式机(windows系统),想要把这些文献同步到云上,然后再从云上同步到平板和其他笔记本电脑比如macbook。文献同步虽已成功,但文献附件都无法打开。 平板报错如下…...
循环队列(C语言)
从今天开始我会开启一个专栏leetcode每日一题,大家互相交流代码经验,也当作我每天练习的自我回顾。第一天的内容是leetcode622.设计循环队列。 一、题目详细 设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO&#…...
Amazon Redshift实用命令语句
1. 数据库管理相关命令 创建数据库 CREATE DATABASE mydatabase;Amazon Redshift创建数据库命令除了基本形式外,还有以下几种带不同参数的形式: 带OWNER参数 可以指定数据库的所有者,通常是一个数据库用户或角色。 CREATE DATABASE myda…...
音频入门(二):音频数据增强
本文介绍了一些常见的音频数据增强方法,并给出了代码实现。 目录 一、简介 二、代码 1. 安装必要的库 2. 代码 3. 各函数的介绍 4. 使用方法 参考: 一、简介 音频数据增强是机器学习和深度学习领域中用于改善模型性能和泛化能力的技术。 使用数据…...
【Hadoop面试题2025】
文章目录 简单题故障及相应的处理方法中等难度高难度小文件小文件的产生小文件问题的影响小文件治理方案推荐方案 冷文件冷文件的产生冷文件问题的影响冷文件治理方案推荐方案 简单题 一、基础概念类 什么是Hadoop? 答案:Hadoop是一个开源的分布式计算框…...
Unity自学之旅03
Unity自学之旅03 Unity自学之旅03📝 碰撞体 Collider 基础定义与作用常见类型OnCollisionEnter 事件碰撞触发器 🤗 总结归纳 Unity自学之旅03 📝 碰撞体 Collider 基础 定义与作用 定义:碰撞体是游戏中用于检测物体之间碰撞的组…...
STranslate 中文绿色版即时翻译/ OCR 工具 v1.3.1.120
STranslate 是一款功能强大且用户友好的翻译工具,它支持多种语言的即时翻译,提供丰富的翻译功能和便捷的使用体验。STranslate 特别适合需要频繁进行多语言交流的个人用户、商务人士和翻译工作者。 软件功能 1. 即时翻译: 文本翻译ÿ…...
树的存储(c++)
树结构相对线性结构来说就⽐较复杂。存储时,既要保存值域,也要保存结点与结点之间的关系。实际中树有很多种存储⽅式:双亲表⽰法,孩⼦表⽰法、孩⼦双亲表⽰法以及孩⼦兄弟表⽰法等。现阶段,我们只⽤掌握孩⼦表⽰法&…...
JVM面试题解,垃圾回收之“对象存活判断”剖析
一、JVM怎么判断一个类/对象是不是垃圾? 先来说如何判断一个对象是不是垃圾 最常用的就是引用计数法和可达性分析 引用计数法 引用计数法为每个对象维护一个计数器来跟踪有多少个引用指向该对象。每当创建一个新的引用指向某个对象时,计数器加1&…...
【Elasticsearch】 Ingest Pipeline `processors`属性详解
在Elasticsearch中,Ingest Pipeline 的 processors 属性是一个数组,包含一个或多个处理器(processors)。每个处理器定义了一个数据处理步骤,可以在数据索引之前对数据进行预处理或富化。以下是对 processors 属性中常见…...
Springboot3 自动装配之核心文件:imports文件
注:本文以spring-boot v3.4.1源码为基础,梳理spring-boot应用启动流程、分析自动装配的原理 如果对spring-boot2自动装配有兴趣,可以看看我另一篇文章: Springboot2 自动装配之spring-autoconfigure-metadata.properties和spring…...
Ceisum无人机巡检直播视频投射
接上次的视频投影,Leader告诉我这个视频投影要用在两个地方,一个是我原先写的轨迹回放那里,另一个在无人机起飞后的地图回显,要实时播放无人机拍摄的视频,还要能转镜头,让我把这个也接一下。 我的天&#x…...
【IJCAI】2025 投稿重点记录
【IJCAI】2025 投稿重点记录 写在最前面【IJCAI】2025 投稿重点记录1. 文件说明2. 论文长度要求正式版本的页面扩展 3. 作者信息及匿名性要求4. 摘要5. 附录与补充内容6. 审稿重点与伦理声明7. 参考文献与贡献声明8. 技术要点与补充细节 🌈你好呀!我是 是…...
U3D的.Net学习
Mono:这是 Unity 最初采用的方式,它将 C# 代码编译为中间语言 (IL),然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP:这是一种较新的方法,它会将 C# 代码先编译为 C 代码,再由 C 编译器…...
C++ 二叉搜索树
目录 概念 性能分析 二叉搜索树的插入 二叉树的查找 二叉树的前序遍历 二叉搜索树的删除(重点) 完整代码 key与value的使用 概念 对于一个二叉搜索树 若它的左子树不为空,则左子树上所有的节点的值都小于等于根节点的值若它的右子树不为空…...
使用HTML5 Canvas 实现呼吸粒子球动画效果的原理
在网页开发领域,动画效果能够极大地提升用户体验,让页面变得更加生动有趣。今天,我们深入剖析一个基于 HTML5 Canvas 的 3D 粒子动画 —— 呼吸粒子球。通过详细解读其代码实现,我们将全面了解如何运用 HTML5 的强大功能构建出如此…...
计算机网络 (56)交互式音频/视频
一、定义与特点 定义:交互式音频/视频是指用户使用互联网和其他人进行实时交互式通信的技术,包括语音、视频图像等多媒体实时通信。 特点: 实时性:音频和视频数据是实时传输和播放的,用户之间可以进行即时的交流。交互…...