核心知识——论文总结
引入
本文我们会针对论文中的核心内容进行总结,加深小伙伴对于Spark的理解。而通过Spark的论文,重点需要掌握理解如下内容:
- Spark 里核心的 RDD 是一个什么概念,它是通过什么方式来优化分布式数据处理的,它的设计思路和计算机科学中的哪些观念比较相像。
- Spark 在系统设计层面,是怎么针对正常情况下和异常情况下的性能进行权衡和选择的。
MapReduce的问题
在上一篇我们有提到,Spark论文的核心就是针对MapReduce明显的不足之处做了改造,在论文的引言里面提到了如下内容:
传统的集群计算框架(如MapReduce和Dryad)虽然在大规模数据分析中被广泛应用,但它们缺乏对分布式内存的有效利用,导致在需要重用中间结果的应用中效率低下。为了解决这一问题,作者提出了弹性分布式数据集(RDDs)这一新的抽象概念。RDDs具有容错性,允许用户显式地将中间结果持久化到内存中,并通过粗粒度转换来高效地实现容错,避免了数据复制和日志记录带来的高开销。基于RDDs的Spark系统在迭代应用中表现出色,比Hadoop快20倍,并且能够支持交互式数据挖掘等新应用。
我们来回忆一下MapReduce的处理流程(细节可见深入MapReduce——全流程重点梳理):Map 函数的输出结果会输出到所在节点的本地硬盘上,Reduce 函数会从 Map 函数所在的节点里拉取它所需要的数据,然后再写入本地。接着通过一个外部排序的过程,把数据进行分组。最后将排序分完组的数据,通过Reduce 函数进行处理。
可以看到在MapReduce处理过程中,任何一个中间环节,都需要去读写硬盘。Map 函数的处理结果,并不会直接通过网络发送给 Reduce 所在的 Worker 节点,Reduce 也不会直接在内存中做数据排序。
而且这还只是单个的MapReduce任务,如论文中提到的,要通过MapReduce来跑一些机器学习任务,比如通过L-BFGS这样的算法,去进行大规模的逻辑回归的模型训练,就需要跑上百个MapReduce的任务。其中每一个MapReduce的任务都差不多,都是把所有日志读入,然后和一个梯度向量做计算,算出新的梯度。接着下一轮计算要再读入一遍原来的日志数据,再和新的梯度做计算。在这个过程中,我们原始的日志,会被重复读取上百遍。这个效率是很差的。
那很容易想到,既然读写磁盘这么浪费时间,那都通过内存处理是不是就行了?
这时候就得考虑,在这个过程中, Map或者Reduce的节点出现故障了怎么办?
因为Reduce对于前面的Map函数有依赖关系,所以任何一个Map节点故障,意味着Reduce只收到了部分数据,而且它还不知道是哪一部分。那么Reduce任务只能失败掉,然后等Map节点重新来过。而且,Reduce的失败,还会导致其他的Map节点计算的数据也要重来一遍,引起连锁反应,最终等于是整个任务重来一遍。这个成本可以说是巨大的。
而且这只是我们尝试让数据不需要落地到硬盘处理中,会遇到的一种情况,我们还可能遇到网络拥塞、内存不足以处理传输的数据等种种情况。事实上传统的MPI分布式计算系统就是这样,让一个节点直接往另外一个节点发送消息来传递数据的,但是这样的系统,容错能力很差,所以集群的规模往往也上不去。
而MapReduce针对这个问题的解决方案非常简单粗暴,那就是把整个数据处理的环节完全拆分开来,然后把一个个阶段的中间数据都落地到硬盘上。这样针对单个节点的故障,我们只需要重新运行对应节点分配的任务就好了,其他已经完成的工作不会“半途而废”。
不过这样的方式很明显不是最优解。
因为虽然在分布式场景下,我们的整个集群规模很大,节点很多,各个节点会出现故障的概率是必然的。但毕竟硬件也好、系统也好,出现故障始终还是小概率事件。正常一个集群里,年度的损坏率通常也就是 1% 左右。我们为了这 1% 的错误,却要把 99% 的数据都反复从硬盘里读出来写进去,感觉的确有点划不来。
Spark的解法
所以很自然地,我们需要有一个更有效率的容错方式。而Spark论文里面总结起来,针对容错做了以下三件事:
- 第一个,提供把数据缓存在内存里的能力。因为如果是计算的中间结果,我们不一定要把它写到硬盘上。如果是反复读取的输入数据,我们可以缓存在内存里而不是每个迭代重新读取一遍。
- 第二个,记录我们运算数据生成的“拓扑图”。也就是记录数据计算的依赖关系,一旦某个节点故障,导致这个依赖关系中的一部分节点出现故障,我们根据拓扑图重新计算这一部分数据就好了。通过这样的方式来解决容错问题,而不是每一次都把数据写入到硬盘。
- 第三个,通过检查点来在特定环节把数据写入到硬盘。当我们的拓扑图层数很深,或者数据要反复进行很多次的迭代计算。前面通过“拓扑图”进行重新计算的容错方式会变得非常低效,那么我们可以在一部分中间环节,把数据写入到硬盘上。这样一种折衷的方式,既避免了每次都去从硬盘读写数据,也避免了一旦某一个环节出现故障,“容错”方案只能完全从头再来的尴尬出现。
以前面提到的大规模逻辑回归的机器模型训练举例,原本需要进行 100轮迭代。我们最好的解决方案,既不是每轮迭代都需要重新读写数据,那样太浪费硬盘的 I/O 了。也不是把几小时的计算过程都放在内存里,那样万一计算梯度结果的数据在第 99 轮丢失了,我们就要从头开始。我们完全可以把读取的日志数据缓存在内存里,然后把每 10 轮计算完的梯度数据写入到硬盘上。这样一旦出现故障,我们只需要重新读取一次日志数据,并最多计算 10轮迭代的过程就好了。
论文 3.2.1 部分使用 Spark 实现分布式逻辑回归的代码如下:
val points = spark.textFile(...).map(parsePoint).persist()
var w = // random initial vector
for (i <- 1 to ITERATIONS) {val gradient = points.map{ p =>p.x * (1/(1+exp(-p.y*(w dot p.x)))-1)*p.y}.reduce((a,b) => a+b)w -= gradient
}
其中输入数据会通过 .persistent 缓存在内存中,而不需要每个迭代都重新从硬盘读取。其实这个思路,就是 Spark 整个系统设计的出发点。根据这个朴素的思路,Spark 定了一个新的概念RDD,全称是 Resilient Distributed Dataset,中文叫做弹性分布式数据集。整个系统设计的其实就是 “弹性”+“分布式”+“数据集” 这三点的组合。分布式和数据集这两个关键字,很好理解,本质就是采用了数据分区的方式,来确保数据是分布式的。
RDD
而 RDD 最核心的设计关键点,就在这个弹性上。论文里的 2.1 部分,给出了 RDD 明确的定义:
Formally, an RDD is a read-only, partitioned collection of records. RDDs can only be created through deterministic operations on either (1) data in stable storage or (2) other RDDs. We call these operations transformations to differentiate them from other operations on RDDs. Examples of transformations include map, filter, and join.
RDDs do not need to be materialized at all times. Instead, an RDD has enough information about how it was derived from other datasets (its lineage) to compute its partitions from data in stable storage. This is a powerful property: in essence, a program cannot reference an RDD that it cannot reconstruct after a failure.Finally, users can control two other aspects of RDDs: persistence and partitioning. Users can indicate which RDDs they will reuse and choose a storage strategy for them (e.g., in-memory storage). They can also ask that an RDD’s elements be partitioned across machines based on a key in each record. This is useful for placement optimizations, such as ensuring that two datasets that will be joined together are hash-partitioned in the same way.
Although individual RDDs are immutable, it is possible to implement mutable state by having multiple RDDs to represent multiple versions of a dataset. We made RDDs immutable to make it easier to describe lineage graphs, but it would have been equivalent to have our abstraction be versioned datasets and track versions in lineage graphs.
翻译:
正式来说,弹性分布式数据集(RDD)是一个只读的、分区的记录集合。RDD只能通过两种方式创建:(1)对稳定存储中的数据进行确定性操作,或(2)对其他RDD进行操作。我们称这些操作为转换,以区分它们与其他RDD操作。转换的例子包括映射、过滤和连接。
RDD不需要始终被物化。相反,RDD拥有足够的信息来记录它是如何从其他数据集(其谱系)中派生的,从而可以从稳定存储中的数据计算出它的分区。这是一个强大的特性:本质上,程序无法引用在故障后无法重建的RDD。
最后,用户可以控制RDD的另外两个方面:持久化和分区。用户可以指示哪些RDD将被重用,并选择它们的存储策略(例如,内存存储)。他们还可以要求根据每个记录中的键将RDD的元素分区到不同的机器上。这对于放置优化非常有用,例如确保将要连接的两个数据集以相同的方式进行哈希分区。
虽然单个RDD是不可变的,但可以通过使用多个RDD来表示数据集的不同版本来实现可变状态。我们将RDD设计为不可变的,以便更容易描述谱系图,但也可以将我们的抽象设计为版本化数据集,并在谱系图中跟踪版本。
其中核心就是,RDD 是只读的、已分区的记录集合,RDD 只能通过明确的操作,以及通过两种数据创建:稳定存储系统中的数据;其他 RDD。这个明确的操作,是指 map、filter 和 join 这样的操作,以和其他的操作区分开来。
按照这个定义,我们可以看到这个是对于数据的一个抽象。我们的任何一个数据集,进行一次转换就是一个新的 RDD,但是这个 RDD 并不需要实际输出到硬盘上。实际上这个数据都不会作为一个完整的数据集缓存在内存中,而只是一个 RDD 的“抽象概念”。只有当我们对某一个 RDD 实际调用 persistent 函数的时候,这个 RDD 才会实际作为一个完整的数据集,缓存在内存中。
一旦被缓存到内存里,这个 RDD 就能够再次被下游的其他数据转换反复使用。一方面,这个数据不需要写入到硬盘,所以我们减少了一次数据写。另一方面,下游的其他转化也不需要再从硬盘读数据,于是,我们就节省了大量的硬盘 I/O 的开销。
我们可以对照着论文 2.2.1 中的示例代码,来看这样一个过程:
lines = spark.textFile("hdfs://...")
errors = lines.filter(_.startsWith("ERROR"))
errors.persist()// Count errors mentioning MySQL:
errors.filter(_.contains("MySQL")).count()// Return the time fields of errors mentioning
// HDFS as an array (assuming time is field
// number 3 in a tab-separated format):
errors.filter(_.contains("HDFS"))
.map(_.split(’\t’)(3))
.collect()
我们从 HDFS 上,读入原始数据,根据关键词 ERROR 进行了一次过滤,然后把它 persistent 下来。而接下来分别有两个分析任务,会用到这个缓存在内存里的 ERROR 数据,一个是找出所有带有 MySQL 关键词的错误日志,然后进行统计行数;另一个则是找到所有带有HDFS 关键字的日志,然后按照 Tab 分割并收集第 3 列的数据。
如上,是论文中的整个流程图,一开始从 HDFS 里读入的 line 数据,因为没有 persistent,所以不会缓存在内存中。而 errors 会缓存在内存里面,供后面两个任务作为输入使用。
errors 我们不需要写入到硬盘里,而后面分析 MYSQL 和 HDFS 关键字错误的两个任务,也不需要从硬盘读数据,数据都是直接在内存中读写,所以性能大大加快了。
从 RDD 的这个逻辑上,其实我们可以看到计算机工程上的其他系统中的影子。
- 第一个是惰性求值(Lazy-Evaluation),我们的一层层数据转化,只要没有调用persistent,都可以先不做计算,而只是记录这个计算过程中的函数。而当 persistent 一旦被调用,那么我们就需要把实际的数据结果计算出来,并存储到内存里,再供后面的数据转换程序调用。
- 第二个是数据库里的视图功能。为了查询方便,对于复杂的多表关联,很多时候我们会预先建好一张数据库的逻辑视图。那么我们在查询逻辑视图的时候,其实还是通过一个多表关联 SQL 去查询原始表的,这个就好像我们并没有调用 persistent,把数据实际持久化下来。当然,我们也可以把对应视图的查询结果,直接写入一张中间表,这样实际上就相当于把计算的结果持久化下来了,后续查询的 SQL 就会查询这个中间表。如果视图里的数据会被后续的 SQL 反复多次查询,并且对应的原始数据集也和 RDD 一样是不可变的话,一样会大大提升系统整体的效率。
宽依赖关系和检查点
虽然通过调用 persistent 来把数据缓存到内存里,减少了大量的硬盘读写,但是我们仍然会面临节点失效,导致 RDD 需要重新计算的情况。
所以 Spark 对这部分流程做了进一步的优化,这个优化说起来其实也不复杂。那就是如果一个节点失效了,导致的数据重新计算,需要影响的节点太多,那么我们就把计算结果输出到硬盘上。而如果影响的节点少,那么我们就只是单独重新计算被响应到的那些节点就好了。
所以在 Spark 里,会对整个数据计算的拓扑图在分布式系统下的依赖关系做一个分类。如果一个 RDD 的一个分区,只会影响到下游的一个节点,那么我们就称这样的上下游依赖关系为窄依赖。而如果一个 RDD 的一个分区,会影响到下游的多个节点,那么我们就称这样的上下游关系为宽依赖。
- 对于窄依赖,即使重算一遍,也只是影响一条线上的少数几个节点,所以对应的中间数据结果,并不需要输出到硬盘上。
- 而对于宽依赖,一旦上游的一个节点失效了,需要重新计算。那么它对应的多个下游节点,都需要重新从这个节点拉取数据并重新计算,需要占用更多的网络带宽和计算资源。换句话说,在宽依赖下,一个上游节点的失效,会以几倍的影响在下游得到放大。所以,在宽依赖的场景下,上游会像 MapReduce 里的 Map 一样,把输出结果序列化到硬盘上,以减少故障后的恢复成本。
同样的,对于有多轮迭代,或者是整个拓扑图很长的数据处理任务,Spark 在persistent 的时候,支持你添加一个 REPLICATE 参数,把当前的计算结果作为一个检查点存储下来。一旦添加了这个参数,数据就不只是存储在内存中,而是会序列化到硬盘里。这样,同样可以减少你在出现故障时候的重新计算的时间。
可以看到,无论是 persistent、宽依赖下的数据会被持久化存储,还是允许用户去自己通过检查点存储中间步骤的计算结果,其本质都是为了在性能和容错间做一个平衡。如果不做任何持久化存储,那么平时系统会跑得很快,但是一旦某个节点出错就要从头再来。而如果都做持久化存储,那么节点出错的时候,计算可以恢复得很快,但是没有问题的时候会有很多浪费。Spark的操作就是在尽可能平衡的同时,给用户更多选择的,以适应不同的业务场景需求。
总结
通过本文的梳理总结,可以看到Spark里的RDD的设计思想并不复杂。和MapReduce一样,RDD的设计思路也是来自于函数式编程。相对于过程式地把每一个数据转换(Transformation)的结果存储下来,RDD相当于记录了输入数据,以及对应的计算输入数据的函数。
而这个方式,和把一步步的计算结果存储下来的效果一样,都可以解决容错问题。当某一个RDD的某一个分区因为故障丢失的时候,我们可以通过输入数据和对应的函数,快速计算出当前RDD的实际内容。而这个输入数据+对应函数的组合,就是RDD中的DAG Lineage图。
RDD和其他分布式系统最大的差异,就在代表弹性的R这个关键字上。
这个弹性体现在两个方面:
- 第一个是数据存储上。 数据不再是存放在硬盘上的,而是可以缓存在内存中。只有当内存不足的时候,才会把它们换出到硬盘上。同时,数据的持久化,也支持硬盘、序列化后的内存存储,以及反序列化后Java对象的内存存储三种形式。虽然需要占用更多的内存,但是计算速度会更快。
- 第二个是选择把什么数据输出到硬盘上。 Spark会根据数据计算的DAG Lineage,来判断某一个RDD对于前置数据是宽依赖,还是窄依赖的。如果是宽依赖的,意味着一个节点的故障,可能会导致大量的数据要进行重新计算,乃至数据网络传输的需求。那么,它就会把数据计算的中间结果存储到硬盘上。
同时,Spark也支持用户定义检查点,能够基于自己的业务场景,把一些关键节点的数据通过检查点的方式,持久化到硬盘上,避免出现特定节点的故障,导致大量数据需要重新计算的问题。
总的说起来,Spark的RDD 支持了MapReduce可以支持的所有运算方式。并且还通过尽可能利用内存,使得需要多个MapReduce的组合或者迭代的任务的执行速度大大加快了。从论文里展示的分布式逻辑回归处理效果来看,Spark的性能会比使用原始的MapReduce一轮轮迭代快上20倍。这也是为什么,Spark一出现在市场上,就很快替代了大量的MapReduce的分析工作,并在迭代式的机器学习算法中成为了主流。
相关文章:
核心知识——论文总结
引入 本文我们会针对论文中的核心内容进行总结,加深小伙伴对于Spark的理解。而通过Spark的论文,重点需要掌握理解如下内容: Spark 里核心的 RDD 是一个什么概念,它是通过什么方式来优化分布式数据处理的,它的设计思路…...
HTTP 核心知识点整理
1. HTTP 基础 定义:HTTP(HyperText Transfer Protocol)是应用层协议,基于 请求-响应模型,用于客户端(浏览器)与服务器之间的通信。特点: 无状态:每次请求独立&a…...
什么是矩阵账号
矩阵账号是指在同一平台或多个平台上,围绕同一品牌或个人,创建的多个相互关联、协同工作的账号组合。这些账号虽然独立,但在内容定位和运营策略上有所区分,同时又相互引流,共同形成一个网络结构,类似于矩阵…...
【6】VS Code 新建上位机项目---项目分层
【6】VS Code 新建上位机项目---项目分层 1 项目分层(layer)2 项目分层实现数据插入SQL3 项目分层实现 (实体类封装参数)4 项目分层的实现SQL查询数据1 项目分层(layer) 表示层(UI):与用户交互使用。比如按钮,输入信息等;业务层(BLL):传递数据,业务逻辑。根据用户需…...
EspressoSample深度解析:在CircleCI上高效运行Android UI测试
项目背景与简介 EspressoSample项目位于GitHub上的circleci/EspressoSample仓库,该项目旨在展示如何在CircleCI平台上配置和使用Espresso进行Android应用的UI测试。 项目结构与环境准备 项目结构 EspressoSample项目遵循典型的Android项目结构,包含a…...
【每日论文】MetaSpatial: Reinforcing 3D Spatial Reasoning in VLMs for the Metaverse
下载PDF或查看论文,请点击: LlamaFactory - huggingface daily paper - 每日论文解读 | LlamaFactory | LlamaFactory探索LlamaFactory,为你解读AI前沿技术文章,快速掌握最新技术动态https://www.llamafactory.cn/daily-paper/de…...
mac m4 Homebrew安装MySQL 8.0
1.使用Homebrew安装MySQL8 在终端中输入以下命令来安装MySQL8: brew install mysql8.0 安装完成后,您可以通过以下命令来验证MySQL是否已成功安装: 2.配置mysql环境变量 find / -name mysql 2>/dev/null #找到mysql的安装位置 cd /op…...
Java关于多态
多态 字面意思:对象的多种形态。 Student(子类)<-Person(父类)->Teacher(子类) Student snew Student(); 学生形态 对象 代表用new创建一个学生对象赋值给Student 类型,代表Student类型(学生对象)现在是学生形态。 有了多态之后ÿ…...
K8S学习之基础四十六:k8s中部署Kibana
部署kibana组件 上传kibina镜像到harbor 部署kibana组件,包括svc和deplomentvi kibana.yaml apiVersion: v1 kind: Service metadata:name: kibananamespace: kube-logginglabels:app: kibana spec:ports:- port: 5601selector:app: kibana --- apiVersion: apps/…...
如何快速对比两个不同的excel文件中的单元格的数据是否完全相同 并把不同的单元格的背景颜色更改为红色?
要快速对比两个不同的Excel文件中的单元格数据是否完全相同,并将不同的单元格背景颜色更改为红色,可以使用Excel的以下几种方法: 方法一:使用条件格式 打开两个Excel文件。将一个文件的内容复制到另一个文件的新工作表中&#x…...
基于Python+LanceDB实战向量搜索
本篇实战演示向量搜索的实现和示例。 预期效果 给出一个查询的字符串,通过向量搜索,在下面三个语句中搜索出关联性最大的那句。 "熊猫是中国的国宝,主要栖息在四川山区。","长城是古代中国建造的军事防御工事,全…...
多路转接epoll
目录 一、为什么epoll最高效? 二、epoll的三个系统调用 三、理解epoll模型 四、epoll的优点 五、epoll的使用示例 六、epoll的工作模式 ET模式和LT模式的对比 七、epoll的使用场景 总结 一、为什么epoll最高效? 按照 man 手册的…...
AI编程工具哪家强?对比Cusor、Copilot、Cline
前言 AI最先革谁的命?刚毕业参加工作的那个时候就在想是否可以开发一个程序让它自己写代码,在那个遥远的年代,这种想法仿佛就是天方夜谭。但是今天大模型的出现让理想成为了现实。回答前面的问题,AI最先革谁的命,最聪…...
[FPGA基础学习]实现流水灯与按键暂停
FPGA实现LED流水灯 1.vscode的安装和使用 vscode下载 Visual Studio Code - Code Editing. Redefined vscode插件(Verilog-HDL/SystemVerilog)下载 quartus绑定vscode 2.用6个LED完成周期为1秒的跑马灯效果 流水灯模块设计 时钟输入 DE2-115开发板…...
刷题记录(LeetCode 994.腐烂的橘子)
在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一: 值 0 代表空单元格;值 1 代表新鲜橘子;值 2 代表腐烂的橘子。 每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格中没有…...
ECharts折线图源码合集1(共18个自定义图表),附视频讲解与代码下载
引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我整理了18个自定义折线图图表,不仅对每个图表代码进行了精简优化,剥离冗余配置项,…...
SQL小菜之TOP N查找问题
前言 SQL的编写是后端面试中非常常见,其中TOP N查找问题也是高频出现的问题,今天我们来看两道SQL TOPN问题。 问题 我们有一张雇员表Employee: CREATE TABLE Employee (id int DEFAULT NULL,salary int DEFAULT NULL,department varchar(…...
蓝桥杯 临时抱佛脚 之 二分答案法与相关题目
二分答案法(利用二分法查找区间的左右端点) (1)估计 最终答案可能得范围 是什么 (2)分析 问题的答案 和 给定条件 之间的单调性,大部分时候只需要用到 自然智慧 (3)建…...
Css环形旋转立体感动画
Css环形旋转立体感动画 index.html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>Css环形旋转立体感动画</title><link rel"stylesheet" href"./style.css">&l…...
音乐极客指南:Melody高音质私有云音乐平台本地部署方案
文章目录 前言1. 添加镜像源2. 本地部署Melody3. 本地访问与使用演示4. 安装内网穿透5. 配置Melody公网地址6. 配置固定公网地址 前言 嘿,各位音乐爱好者们!今天我要带大家玩个大招——在香橙派Zero3上搭建你的专属在线音乐平台,还能通过cpo…...
Microi吾码界面设计引擎之基础组件用法大全【内置组件篇·中】
🎀🎀🎀 microi-pageengine 界面引擎系列 🎀🎀🎀 一、Microi吾码:一款高效、灵活的低代码开发开源框架【低代码框架】 二、Vue3项目快速集成界面引擎 三、Vue3 界面设计插件 microi-pageengine …...
# WebSocket 与 Socket.IO 对比与优化
核心概念对比 WebSocket 协议性质:HTML5 提供的全双工通信协议 (RFC 6455)连接方式:基于 TCP 的低层协议通信模式:持久化连接,服务端可主动推送协议升级:通过 HTTP 101 状态码切换协议 Socket.IO 协议性质…...
vue3中,route4,获取当前页面路由的问题
首先应用场景如下: 在main.js里面,引入的是路由的配置文件,如下: import {router} from /router; app.use(router); 路由配置文件router.js如下: import { createRouter, createWebHistory } from vue-router; imp…...
python将整个txt文件写入excel的一个单元格?
要将整个txt文件写入Excel的一个单元格,可以使用Python的openpyxl库来实现。以下是一个简单的示例代码: from openpyxl import Workbook# 读取txt文件内容 with open(file.txt, r) as file:txt_content file.read()# 创建一个新的Excel工作簿 wb Work…...
日志2333
Pss-9 这一关考察的是时间盲注 先练习几个常见命令语句: select sleep(5);--延迟5s输出结果 if (1>0,ture,false);--输出‘ture’ /if (1<0,ture,false);--输出‘false’ select ascii()/select ord()返回字…...
用Deepseek写扫雷uniapp小游戏
扫雷作为Windows系统自带的经典小游戏,承载了许多人的童年回忆。本文将详细介绍如何使用Uniapp框架从零开始实现一个完整的扫雷游戏,包含核心算法、交互设计和状态管理。无论你是Uniapp初学者还是有一定经验的开发者,都能从本文中获得启发。 …...
C++中的异常和智能指针
一、C中的异常 1.1C语言中关于错误的处理(回顾) 1.1.1处理一:文件中的错误码,错误信息 C语言中,文件打开成功则返回地址,不成功返回0 FILE* foutfopen("Test.txt","r"); cout<&…...
Selenium 简单入门操作示例
最简单的 Selenium 示例(Python版) 下面是一个完整的、最简单的 Selenium 操作示例,带你快速上手: from selenium import webdriver from selenium.webdriver.common.by import By import time# 1. 启动浏览器(这里使…...
6.1 模拟专题:LeetCode 1576. 替换所有的问号
1. 题目链接 LeetCode 1576. 替换所有的问号 2. 题目描述 给定一个仅包含小写字母和问号 ? 的字符串 s,要求将所有 ? 替换为任意小写字母,使得替换后的字符串中 没有相邻的两个字符相同。 示例: 输入:s "?zs" →…...
前端知识点---用正则表达式判断邮箱(javascript)
// 全面的正则(兼容大多数情况) const emailRegex /^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}$/;// 或直接使用浏览器内置验证 <input type"email" required>/:正则表达式的起始和结束标志。 ^:匹配字符串的…...
深度剖析 Spring 源码 性能优化:核心原理与最佳实践
深度剖析 Spring 源码 & 性能优化:核心原理与最佳实践 🚀 Spring 框架 作为 Java 生态的核心技术,广泛应用于企业级开发。但很多开发者只会“用”Spring,而不深入其内部原理,导致无法高效排查问题 & 进行性能优…...
Axure RP9教程 :轮播图(动态面板) | 头部锁定
文章目录 引言I 轮播图操作步骤在画布中添加一个动态面板设置面板状态II 头部锁定将头部区域选中,右键组合或用Ctrl+G快捷键;将组合的头部区域,右键创建动态面板;引言 动态面板的功能十分强大,比如:拥有独立的内部坐标系,有多个状态; Banner的案例中会用到动态面板多个…...
rabbitmq承接MES客户端服务器
文章目录 背景整体架构概述方案详细步骤1. 数据库选型与搭建2. 设备端数据上传至数据库3. 搭建 RabbitMQ 服务器4. 数据同步模块(数据库到 RabbitMQ)5. MES 服务器从 RabbitMQ 接收数据6. 指令接收模块(RabbitMQ 到设备端) 7. MES…...
重学vue3(三):vue3基本语法及使用
组合式 API是vue3 的核心特性,替代 Vue2 的选项式 API,强调逻辑复用和代码组织。基本语法如下: <script setup> import { ref, reactive, computed, onMounted } from vue;// 1. 响应式数据 const count ref(0); // 基本类…...
算法 | 麻雀搜索算法原理,公式,改进算法综述,应用场景及matlab完整代码
一、麻雀搜索算法(SSA)原理 1. 算法基础 麻雀搜索算法(Sparrow Search Algorithm, SSA)是2020年提出的一种群体智能优化算法,灵感来源于麻雀群体的觅食与反捕食行为。算法将麻雀分为三类角色:发现者(Producer):适应度最高,负责探索全局最优区域;加入者(Follower)…...
0322-数据库与前后端的连接、数据库表的增删改查
前端 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>Insert title here</title> <script srcjs/jquery-3.7.1.min.js></script> <script> //jquaryajax发起请求 //传参形式不同 post用data{}…...
详细介绍Qt中用于断言的宏 Q_ASSERT
Q_ASSERT 是 Qt 框架中用于调试的核心宏之一,其作用类似于标准 C/C 的 assert,但针对 Qt 的特性进行了优化。它用于在开发阶段验证程序的逻辑正确性,帮助开发者快速定位潜在的错误。 1.基本用法 Q_ASSERT(condition);功能:在调试…...
基于Python的自然语言处理系列(60):使用 LangChain 构建 Multi-Vector Retriever 进行文档检索
在 NLP 和 AI 领域,基于嵌入(Embeddings)进行文档检索已成为一种高效的解决方案。本文介绍如何使用 LangChain 构建 Multi-Vector Retriever,实现对长文档的分块索引和高效检索。 1. 环境准备 首先,我们需要安装相关…...
Dify 部署指南-离线版
Docker 部署 1、 访问 Docker 官网 (https://www.docker.com/) 获取安装包。 2、 上传 Docker 安装包 3、 进入解压目录,执行解压命令 tar xzvf docker-28、0.2、tgz4、 将解压文件中的 Docker 相关文件移动到 /usr/bin/ 目录 sudo cp docker/* /usr/bin/5、 创建…...
解决 Element UI 嵌套弹窗的状态管理问题!!!
解决 Element UI 嵌套弹窗的状态管理问题 🔧 问题描述 ❓ 在使用 Element UI 开发一个多层嵌套弹窗功能时,遇到了以下问题: 弹窗只能打开一次,第二次点击无法打开 🚫收到 Vue 警告:避免直接修改 prop 值…...
基于STM32单片机的智能手环/音乐播放/语音识别
基于STM32单片机的智能手环/音乐播放/语音识别 持续更新,欢迎关注!!! ** 基于STM32单片机的智能手环/音乐播放/语音识别 ** 21世纪,社会高速发展,生活物质越来越丰富,随着科技的进步,智能化成为了人们关注的焦点&am…...
NFC 智能门锁全栈解决方案:移动端、服务器、Web 管理平台
目录 一、系统整体架构 二、移动端 APP 开发 2.1 开发环境与基础准备 2.2 主要功能模块 2.3 示例代码(Android/Kotlin 简化示例) 三、后台服务开发 3.1 环境准备 3.2 主要功能 3.3 示例代码(Node.js Express 简化示例) …...
使用 Python 开发 MCP Server 及 Inspector 工具详解
使用 Python 开发 MCP Server 及 Inspector 工具详解 前言 模型上下文协议 (Model Context Protocol, MCP) 是一种新兴的协议,旨在让大型语言模型 (LLM) 更容易地与外部工具和服务集成。本文将介绍如何使用 Python 开发一个 MCP Server,并详细讲解如何使…...
论坛系统测试报告
一、项目背景 为论坛系统项目设计并进行自动化测试。论坛系统由六个页面构成:用户登录页、用户注册页、个人中心页面、我的帖子页面、帖子编辑页、帖子列表页以及帖子详情页。 通过使用selenium工具来定位到web中的元素,对获取到的元素进行自动化测试等操…...
Android一个APP里面最少有几个线程
Android应用启动时,默认会创建一个进程,该进程中最少包含5个系统自动创建的线程,具体如下: Main线程(主线程/UI线程) 负责处理用户交互、UI更新等核心操作,所有与界面相关的逻辑必须在此线程执行。若在此线程执行耗时操作(如网络请求),会导致界面卡顿甚至触发ANR(应…...
DML 数据操纵语言学习笔记
一、DML 核心概念体系 1.1 语言定位与边界 DML(Data Manipulation Language)作为 SQL 三大核心语言之一,专注于数据行级操作,区别于 DDL(结构定义)和 DCL(权限控制)。其核心指令包…...
7-Zip 功能介绍
7-Zip 是一款开源、高效的文件压缩与解压缩工具,支持多种格式,以高压缩率和灵活性著称。以下是其核心功能: 多格式支持 压缩 / 解压:支持 7z(默认格式,压缩率极高)、ZIP、RAR、GZIP、BZIP2、TAR…...
《基于python游戏设计与实现》开题报告
个人主页:@大数据蟒行探索者 一、研究背景、目的及意义 (一)研究背景 游戏的普及与成功:随着智能手机的普及和网络技术的发展,手机游戏产业逐渐成熟,成为娱乐文化产业的重要组成部分。《开心消消乐》作为一款休闲类游戏,自上线以来凭借其简单易上手的玩法和丰富的…...
鸿蒙学习笔记(3)-像素单位、this指向问题、RelativeContainer布局、@Style装饰器和@Extend装饰器
一、像素单位 物理像素:用px表示。 逻辑像素:在布局的时候,底层针对物理像素和屏幕尺寸关系进行转化的中间层。 分辨率:代表在屏幕上到底布局了多少了像素点(发光点) 官方同时也提供了相关单位,在开发中…...
Selenium之简介
Selenium简介 首先,让我们看看官网是怎么定义的 Selenium是一个支持web浏览器自动化的一系列工具和库的综合项目,提供了扩展来模拟用户和浏览器的交互,用于扩展浏览器分配的分发服务器;用于W3C WebDriver规范的基础架构 其实&a…...