【Spark精讲】Spark Shuffle详解
目录
Shuffle概述
Shuffle执行流程
总体流程
中间文件
ShuffledRDD生成
Stage划分
Task划分
Map端写入(Shuffle Write)
Reduce端读取(Shuffle Read)
Spark Shuffle演变
SortShuffleManager运行机制
普通运行机制
bypass 运行机制
Tungsten Sort Shuffle 运行机制
基于Sort的Shuffle机制的优缺点
Shuffle调优
广播变量
shuffle参数调优
spark.shuffle.file.buffer
spark.reducer.maxSizeInFlight
spark.shuffle.io.maxRetries
spark.shuffle.io.retryWait
spark.shuffle.memoryFraction
spark.shuffle.manager
spark.shuffle.sort.bypassMergeThreshold
spark.shuffle.consolidateFiles
Shuffle概述
我们知道,Spark的Shuffle与Hadoop中的MapReduce过程有很多相似之处,但也有自己的优势。Spark在Shuffle过程中权衡内存与磁盘间的使用,尽最大努力将数据在内存中进行分组、排序等。当内存不足时Spark也可以将数据溢写到磁盘中而且实现相同的功能,这也体现了RDD的弹性之处。
Shuffle的本质是数据重组分发的过程。
Shuffle 定义:集群范围内跨节点、跨进程的数据分发。
Shuffle过程中集群会需要大量资源进行磁盘和网络的I/O。在DAG的计算链条中,Shuffle环节的执行性能往往是最差的。
做个通俗的比喻,类比橘子分练机,RDD的分练机就是Partitioner。
举个例子:
line.flatMap(_.split(" ")).map((_, 1))
.reduceByKey(_+_).collect().foreach(println)
以Shuffle为边界,reduceByKey的计算被切割为两个执行阶段。Shuffle之前的Stage叫作Map阶段,而把Shuffle之后的 Stage称作Reduce阶段。在Map阶段,每个Executors先把自己负责的数据分区做初步聚合(又叫 Map 端聚合、局部聚合);在Shuffle环节,不同的单词被分发到不同节点的Executors中;最后的Reduce阶段,Executors以单词为Key做第二次聚合,从而完成统计计数的任务。如下图所示。
Shuffle执行流程
总体流程
根据Shuffle(宽依赖,即ShuffleDependency)划分前后两个Stage,前一个Stage(Stage1)中,将数据按key进行分组,写入本节点的BlockManager管理的文件中。每个分区Map端输出的保存位置存储在MapOutputTrackerMaster中,后一个Stage(Stage2)中计算某个分区的数据时,首先会通过MapOutputTrackerMaster找到该分区的数据都在哪些节点上,再拉取相应节点的数据,完成Stage2中的数据的加载,进而执行后续的RDD的转换。
MapOutputTracker组件也是主从架构,在Driver中为MapOutputTrackerMaster,在Executor中为MapOutputTrackerWorker。Master中保存了每个Shuffle的Map端每个分区的输出信息。Worker通过与Master通信获取某个Shuffle的Reduce端对应的Map端数据保存在哪些节点中。
中间文件
Map阶段与Reduce阶段,通过生产与消费Shuffle中间文件的方式,来完成集群范围内的数据交换。
在Map执行阶段,每个Task(以下简称 Map Task)都会生成包含data 文件与index文件的Shuffle中间文件。也就是说,Shuffle 文件的生成,是以Map Task为粒度的,Map阶段有多少个Map Task,就会生成多少份Shuffle中间文件。
ShuffledRDD生成
scala> sc.textFile("/root/tmp/a.txt",3).flatMap(x=>x.split(",")).map(x=>(x,1)).reduceByKey((a,b)=>a+b)
val res2: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[10] at reduceByKey at <console>:1
reduceByKey默认使用的是 HashPartitioner (相当于橘子分拣器)。除了Partitioner,此外生成ShuffledRDD时还需要传入Aggregator(可用于Map端聚合和Reduce端聚合),Serializer(如KryoSerializer)等。
ShuffledRDD 调用 getDependencies 方法获取依赖返回的是 ShuffleDependency,ShuffleDependency 里依赖的父RDD即为调用算子时的RDD。
ShuffledRDD的计算函数与其他窄依赖的计算函数也不同,普通map()函数执行时,计算某分区的数据时,只需对父RDD的某分区数据进行转换即可。但ShuffledRDD某分区计算时,必须到不同的节点拉取对应分区的结果才能完成该分区数据的加载。
Stage划分
Task划分
Stage划分完成后,每个Stage会根据计算的RDD的分区数量划分多少个Task,每个Task计算RDD的一个分区的数据。ShuffleMapStage中划分的Task为ShuffleMapTask,ShuffleMapTask会被序列化到Executor节点中进行执行,ShuffleMapTask的执行会将该分区的数据进行分组,如果需要Map端聚合在分组过程中则还会进行聚合操作。最终将分组的数据写入到所在节点的文件中。
Map端写入(Shuffle Write)
Shuffle写入临时文件的过程叫做:Shuffle Write
。
Spark现支持三种writer,分为BypassMergeSortShuffleWriter, SortShuffleWriter 和 UnsafeShuffleWriter。
每种Shuffle witer都有非常复杂的实现机制。如果你对Shuffle的底层实现非常感兴趣可以参考:
https://blog.csdn.net/wendelee/article/details/109818711
在生成中间文件的过程中,Spark 会借助一种类似于 Map 的数据结构,来计算、缓存并排序数据分区中的数据记录。这种 Map 结构的 Key 是(Reduce Task Partition ID,Record Key)的二元组,而 Value 是原数据记录中的数据值。
总结下来,Shuffle 中间文件的生成过程,分为如下几个步骤:
- 对于数据分区中的数据记录,逐一计算其目标分区,然后填充内存数据结构;
- 当数据结构填满后,如果分区中还有未处理的数据记录,就对结构中的数据记录按(目标分区 ID,Key)排序,将所有数据溢出到临时文件,同时清空数据结构;
- 重复前 2 个步骤,直到分区中所有的数据记录都被处理为止;
- 对所有临时文件和内存数据结构中剩余的数据记录做归并排序,生成数据文件和索引文件。
Reduce端读取(Shuffle Read)
对于所有 Map Task 生成的中间文件,Reduce Task 需要通过网络从不同节点的硬盘中下载并拉取属于自己的数据内容。不同的 Reduce Task 正是根据 index 文件中的起始索引来确定哪些数据内容是属于自己的。这个拉取数据的过程被叫做Shuffle Read。
Shuffle Reader的实现都被封装在了BlockStoreShuffleReader
。
整个Reader的流程主要是:
- 首先新建ShuffleBlockFetcherIterator获取数据迭代器,会返回(blockId, inputStream)的数据迭代器;
- 对每个block数据进行压缩和加密操作,是通过serializerManager进行的,对每个block数据进行反序列化,反序列化输入流成为<K,V>数据迭代器;
- 对迭代器添加监控和数据处理完成后的清洗函数处理工作;
- 如果要进行聚合操作,会对各个map的当前reduceId的数据进行聚合;
- 如果需要排序,对聚合后的数据进行排序操作。
需要特别注意的是,Shuffle Reader过程可以从两个地方来读取数据块,一个是本地的block,一个是远程的block。远程的block读取是通过向BlockTransferService这个服务发送读取数据块请求来获取数据数据。那么如何区分是从本地读,还是从远程读取呢?
是通过每个块的executorID来区分的,本地环境的executorID和块的id相等就是从本地读,若不相等就会从远端节点读取数据。
Spark Shuffle演变
我们可以看到,从Spark2.0以后,Hash Based Shuffle退出了历史舞台,本着过时不讲的原则,我们来看一下SortShuffleManager的运行机制。
目前Spark2.0及以上的版本,Shuffle框架主要包括以下几个部分:
- ShuffleManager
这是一个接口,负责管理shuffle相关的组件,比如:通过它来注册shuffle的操作函数,获取writer和reader等。在sparkenv中注册,通过sprkconf进行配置,配置参数是:spark.shuffle.manager,默认是sort,也就是:SortShuffleManager类。在早期的spark版本中,也实现过hashmanager后来全部统一成sort。
- ShuffleReader
在reduce任务中去获取来自多个mapper任务的合并记录数据。实现该接口的类只有一个:BlockStoreShuffleReader。
- ShuffleWriter
在mapper任务中把记录到shuffle系统。这是一个抽象类,实现该抽象类的有:SortShuffleWriter,UnsafeShuffleWriter,BypassMergeSortShuffleWriter三个。
- ShuffleBlockResolver
该接口的实现类需要理解:如何为逻辑的shuffle块标识(map,reduce,shuffle等)获取数据。实现者可以通过文件或文件片段来封装shuffle数据。当获取到shuffle数据时,BlockStore使用它来抽象不同的shuffle实现。该接口的实现类为:IndexShuffleBlockResolver。
SortShuffleManager运行机制
SortShuffleManager的运行机制分为三种:
- 普通运行机制
- bypass运行机制
当 shuffle read task 的数量小于等于spark.shuffle.sort.bypassMergeThreshold
参数的值时(默认为 200),就会启用 bypass 机制; - Tungsten Sort运行机制
开启此运行机制需设置配置项spark.shuffle.manager=tungsten-sort
。但是开启此项配置也不能保证就一定采用此运行机制。
普通运行机制
在该模式下,数据会先写入一个内存数据结构中,此时根据不同的 shuffle 算子,可能选用不同的数据结构。如果是 reduceByKey 这种聚合类的 shuffle 算子,那么会选用 Map 数据结构,一边通过 Map 进行聚合,一边写入内存;如果是 join 这种普通的 shuffle 算子,那么会选用 Array 数据结构,直接写入内存
。接着,每写一条数据进入内存数据结构之后,就会判断一下,是否达到了某个临界阈值。如果达到临界阈值的话,那么就会尝试将内存数据结构中的数据溢写到磁盘,然后清空内存数据结构。
在溢写到磁盘文件之前,会先根据 key 对内存数据结构中已有的数据进行排序。排序过后,会分批将数据写入磁盘文件。默认的 batch 数量是 10000 条,也就是说,排序好的数据,会以每批 1 万条数据的形式分批写入磁盘文件
。写入磁盘文件是通过 Java 的 BufferedOutputStream 实现的。BufferedOutputStream
是 Java 的缓冲输出流,首先会将数据缓冲在内存中,当内存缓冲满溢之后再一次写入磁盘文件中,这样可以减少磁盘 IO 次数,提升性能。
一个 task 将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并,这就是merge 过程,此时会将之前所有临时磁盘文件中的数据读取出来,然后依次写入最终的磁盘文件之中。此外,由于一个 task 就只对应一个磁盘文件,也就意味着该 task 为下游 stage 的 task 准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个 task 的数据在文件中的 start offset 与 end offset。
SortShuffleManager
由于有一个磁盘文件 merge 的过程,因此大大减少了文件数量。比如第一个 stage 有 50 个 task,总共有 10 个 Executor,每个 Executor 执行 5 个 task,而第二个 stage 有 100 个 task。由于每个 task 最终只有一个磁盘文件,因此此时每个 Executor 上只有 5 个磁盘文件,所有 Executor 只有 50 个磁盘文件。
普通运行机制的 SortShuffleManager 工作原理如下图所示:
bypass 运行机制
Reducer 端任务数比较少的情况下,基于Hash Shuffle
实现机制明显比基于Sort Shuffle
实现机制要快,因此基于Sort huffle
实现机制提供了一个回退方案,就是 bypass 运行机制。对于 Reducer 端任务数少于配置属性spark.shuffle.sort.bypassMergeThreshold
设置的个数时,使用带 Hash 风格的回退计划。
bypass 运行机制的触发条件如下:
- shuffle map task 数量小于
spark.shuffle.sort.bypassMergeThreshold=200
参数的值。 - 不是聚合类的 shuffle 算子。
此时,每个 task 会为每个下游 task 都创建一个临时磁盘文件,并将数据按 key 进行 hash 然后根据 key 的 hash 值,将 key 写入对应的磁盘文件之中。当然,写入磁盘文件时也是先写入内存缓冲,缓冲写满之后再溢写到磁盘文件的。最后,同样会将所有临时磁盘文件都合并成一个磁盘文件,并创建一个单独的索引文件。
该过程的磁盘写机制其实跟未经优化的HashShuffleManager
是一模一样的,因为都要创建数量惊人的磁盘文件,只是在最后会做一个磁盘文件的合并而已。因此少量的最终磁盘文件,也让该机制相对未经优化的HashShuffleManager
来说,shuffle read
的性能会更好。
而该机制与普通SortShuffleManager
运行机制的不同在于:第一,磁盘写机制不同;第二,不会进行排序。也就是说,启用该机制的最大好处在于,shuffle write
过程中,不需要进行数据的排序操作,也就节省掉了这部分的性能开销。
bypass
运行机制的SortShuffleManager
工作原理如下图所示:
Tungsten Sort Shuffle 运行机制
基于 Tungsten Sort 的 Shuffle 实现机制主要是借助 Tungsten 项目所做的优化来高效处理 Shuffle。
Spark 提供了配置属性,用于选择具体的 Shuffle 实现机制,但需要说明的是,虽然默认情况下 Spark 默认开启的是基于 SortShuffle 实现机制,但实际上,参考 Shuffle 的框架内核部分可知基于 SortShuffle 的实现机制与基于 Tungsten Sort Shuffle 实现机制都是使用 SortShuffleManager,而内部使用的具体的实现机制,是通过提供的两个方法进行判断的:
对应非基于 Tungsten Sort 时,通过 SortShuffleWriter.shouldBypassMergeSort 方法判断是否需要回退到 Hash 风格的 Shuffle 实现机制,当该方法返回的条件不满足时,则通过 SortShuffleManager.canUseSerializedShuffle 方法判断是否需要采用基于 Tungsten Sort Shuffle 实现机制,而当这两个方法返回都为 false,即都不满足对应的条件时,会自动采用普通运行机制。
因此,当设置了spark.shuffle.manager=tungsten-sort
时,也不能保证就一定采用基于 Tungsten Sort 的 Shuffle 实现机制。
要实现 Tungsten Sort Shuffle 机制需要满足以下条件:
- Shuffle 依赖中不带聚合操作或没有对输出进行排序的要求。
- Shuffle 的序列化器支持序列化值的重定位(当前仅支持 KryoSerializer Spark SQL 框架自定义的序列化器)。
- Shuffle 过程中的输出分区个数少于 16777216 个。
实际上,使用过程中还有其他一些限制,如引入 Page 形式的内存管理模型后,内部单条记录的长度不能超过 128 MB (具体内存模型可以参考 PackedRecordPointer 类)。另外,分区个数的限制也是该内存模型导致的。
所以,目前使用基于 Tungsten Sort Shuffle 实现机制条件还是比较苛刻的。
基于Sort的Shuffle机制的优缺点
- 优点
- 小文件的数量大量减少,Mapper 端的内存占用变少;
- Spark 不仅可以处理小规模的数据,即使处理大规模的数据,也不会很容易达到性能瓶颈。
- 缺点
- 如果 Mapper 中 Task 的数量过大,依旧会产生很多小文件,此时在 Shuffle 传数据的过程中到 Reducer 端, Reducer 会需要同时大量地记录进行反序列化,导致大量内存消耗和 GC 负担巨大,造成系统缓慢,甚至崩溃;
- 强制了在 Mapper 端必须要排序,即使数据本身并不需要排序;
- 它要基于记录本身进行排序,这就是
Sort-Based Shuffle
最致命的性能消耗。
Shuffle调优
广播变量
在数据关联场景中,广播变量是克制 Shuffle 的杀手锏。
一个形象的图例如下:
在广播变量的运行机制下,普通变量存储的数据封装成广播变量,由 Driver 端以 Executors 为粒度进行分发,每一个 Executors 接收到广播变量之后,将其交由 BlockManager管理。
当然使用广播变量也有很多的制约,例如:
当创建完广播变量,后续不可以对广播变量进行修改,保证所有的节点都能获得相同的广播变量。
在数据量较大的情况下,Driver可能会成为瓶颈
shuffle参数调优
spark.shuffle.file.buffer
- 默认值:32k
- 参数说明:该参数用于设置shuffle write task的BufferedOutputStream的buffer缓冲大小。将数据写到磁盘文件之前,会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。
- 调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。
spark.reducer.maxSizeInFlight
- 默认值:48m
- 参数说明:该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。
- 调优建议:如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如96m),从而减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。
spark.shuffle.io.maxRetries
- 默认值:3
- 参数说明:shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,是会自动进行重试的。该参数就代表了可以重试的最大次数。如果在指定次数之内拉取还是没有成功,就可能会导致作业执行失败。
- 调优建议:对于那些包含了特别耗时的shuffle操作的作业,建议增加重试最大次数(比如60次),以避免由于JVM的full gc或者网络不稳定等因素导致的数据拉取失败。在实践中发现,对于针对超大数据量(数十亿~上百亿)的shuffle过程,调节该参数可以大幅度提升稳定性。
spark.shuffle.io.retryWait
- 默认值:5s
- 参数说明:具体解释同上,该参数代表了每次重试拉取数据的等待间隔,默认是5s。
- 调优建议:建议加大间隔时长(比如60s),以增加shuffle操作的稳定性。
spark.shuffle.memoryFraction
- 默认值:0.2
- 参数说明:该参数代表了Executor内存中,分配给shuffle read task进行聚合操作的内存比例,默认是20%。
- 调优建议:在资源参数调优中讲解过这个参数。如果内存充足,而且很少使用持久化操作,建议调高这个比例,给shuffle read的聚合操作更多内存,以避免由于内存不足导致聚合过程中频繁读写磁盘。在实践中发现,合理调节该参数可以将性能提升10%左右。
spark.shuffle.manager
- 默认值:sort
- 参数说明:该参数用于设置ShuffleManager的类型。Spark 1.5以后,有三个可选项:hash、sort和tungsten-sort。HashShuffleManager是Spark 1.2以前的默认选项,但是Spark 1.2以及之后的版本默认都是SortShuffleManager了。tungsten-sort与sort类似,但是使用了tungsten计划中的堆外内存管理机制,内存使用效率更高。
- 调优建议:由于SortShuffleManager默认会对数据进行排序,因此如果你的业务逻辑中需要该排序机制的话,则使用默认的SortShuffleManager就可以;而如果你的业务逻辑不需要对数据进行排序,那么建议参考后面的几个参数调优,通过bypass机制或优化的HashShuffleManager来避免排序操作,同时提供较好的磁盘读写性能。这里要注意的是,tungsten-sort要慎用,因为之前发现了一些相应的bug。
spark.shuffle.sort.bypassMergeThreshold
- 默认值:200
- 参数说明:当ShuffleManager为SortShuffleManager时,如果shuffle read task的数量小于这个阈值(默认是200),则shuffle write过程中不会进行排序操作,而是直接按照未经优化的HashShuffleManager的方式去写数据,但是最后会将每个task产生的所有临时磁盘文件都合并成一个文件,并会创建单独的索引文件。
- 调优建议:当你使用SortShuffleManager时,如果的确不需要排序操作,那么建议将这个参数调大一些,大于shuffle read task的数量。那么此时就会自动启用bypass机制,map-side就不会进行排序了,减少了排序的性能开销。但是这种方式下,依然会产生大量的磁盘文件,因此shuffle write性能有待提高。
spark.shuffle.consolidateFiles
注意:Spark 2.0已经看不到HashShuffleManager类了。
- 默认值:false
- 参数说明:如果使用HashShuffleManager,该参数有效。如果设置为true,那么就会开启consolidate机制,会大幅度合并shuffle write的输出文件,对于shuffle read task数量特别多的情况下,这种方法可以极大地减少磁盘IO开销,提升性能。
- 调优建议:如果的确不需要SortShuffleManager的排序机制,那么除了使用bypass机制,还可以尝试将spark.shffle.manager参数手动指定为hash,使用HashShuffleManager,同时开启consolidate机制。在实践中尝试过,发现其性能比开启了bypass机制的SortShuffleManager要高出10%~30%。
相关文章:
【Spark精讲】Spark Shuffle详解
目录 Shuffle概述 Shuffle执行流程 总体流程 中间文件 ShuffledRDD生成 Stage划分 Task划分 Map端写入(Shuffle Write) Reduce端读取(Shuffle Read) Spark Shuffle演变 SortShuffleManager运行机制 普通运行机制 bypass 运行机制 Tungsten Sort Shuffle 运行机制…...
【C++初阶】八、初识模板(泛型编程、函数模板、类模板)
相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) 接上期: 【C初阶】七、内存管理 (C/C内存分布、C内存管理方式、operator new / delete 函数、定位new表达式) -CSDN博客 目录 一 . 泛型编程 二 . 函数模板 函数模板…...
珠海数字孪生赋能工业智能制造,助力制造业企业数字化转型
珠海数字孪生赋能工业智能制造,助力制造业企业数字化转型。数字孪生是利用物理模型、传感器更新及运行历史数据,集成多物理量、多尺度的仿真过程。巨蟹数科数字孪生通过构建物理车间与虚拟车间之间的有效映射并实时反馈机制,实现物理车间与虚…...
HarmonyOS开发实战:如何实现一个运动排名榜页面
HarmonyOS开发实战:如何实现一个运动排名榜页面 代码仓库: 运动排名榜页面 项目介绍 本项目使用声明式语法和组件化基础知识,搭建一个可刷新的排行榜页面。在排行榜页面中,使用循环渲染控制语法来实现列表数据渲染,…...
2019年第八届数学建模国际赛小美赛D题安全选举的答案是什么解题全过程文档及程序
2019年第八届数学建模国际赛小美赛 D题 安全选举的答案是什么 原题再现: 随着美国进入一场关键性的选举,在确保投票系统的完整性方面进展甚微。2016年总统大选期间,唐纳德特朗普因被指控受到外国干涉而入主白宫,这一问题再次成为…...
vivado 创建实施约束
创建实施约束 在您有了一个合成的网表之后,您可以将它与XDC文件一起加载到内存中,或者Tcl脚本已启用以进行实现。当加载XDC以便验证和更正任何不能应用的约束。在某些情况下,合成网表中的对象名称与精心设计。如果是这种情况,则必…...
【代码分析】MPI
代码解读 问题 model/AdaMPI.py:21 为什么下降分辨率model.CPN.unet.FeatMaskNetwork 为什么用的是mask,unet? MPI class MPIPredictor(nn.Module):def __init__(self,width384,height256,num_planes64,):super(MPIPredictor, self).__init__()self.…...
数字孪生Web3D智慧机房可视化运维云平台建设方案
前言 进入信息化时代,数字经济发展如火如荼,数据中心作为全行业数智化转型的智慧基座,重要性日益凸显。与此同时,随着东数西算工程落地和新型算力网络体系构建,数据中心建设规模和业务总量不断增长,机房管理…...
飞天使-docker知识点12-docker-compose
文章目录 docker-compose命令启动单个容器重启容器停止和启动容器停止和启动所有容器演示一个简单示范 docker-compose 部署有依赖问题 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。它允许您使用简单的 YAML 文件来配置应用程序的服务、网络和存储等方…...
快速排序(一)
目录 快速排序(hoare版本) 初级实现 问题改进 中级实现 时空复杂度 高级实现 三数取中 快速排序(hoare版本) 历史背景:快速排序是Hoare于1962年提出的一种基于二叉树思想的交换排序方法 基本思想:…...
GO的sql注入盲注脚本
之间学习了go的语法 这里就开始go的爬虫 与其说是爬虫 其实就是网站的访问如何实现 因为之前想通过go写sql注入盲注脚本 发现不是那么简单 这里开始研究一下 首先是请求网站 这里貌似很简单 package mainimport ("fmt""net/http" )func main() {res, …...
写好ChatGPT提示词原则之:清晰且具体(clear specific)
ChatGPT 的优势在于它允许用户跨越机器学习和深度学习的复杂门槛,直接利用已经训练好的模型。然而,即便是这些先进的大型语言模型也面临着上下文理解和模型固有局限性的挑战。为了最大化这些大型语言模型(LLM)的潜力,关…...
Java实现快速排序及其动图演示
快速排序(Quicksort)是一种基于分治思想的排序算法。它通过选择一个基准元素,将数组分为两个子数组,其中一个子数组的所有元素都小于基准元素,另一个子数组的所有元素都大于基准元素,然后递归地对这两个子数…...
iClient3D 图元操作
1. S3MTilesLayer,S3M(Spatial 3D Model)图层类 S3MTilesLayer,S3M(Spatial 3D Model)图层类,通过该图层实现加载三维切片缓存,包括倾斜摄影模型、BIM模型、点云数据、精细模型、矢量数据、符号等。 那S3MTilesLayer中针对图元的…...
从0到1!开发小白快速入门腾讯云数据库
在这个海量数据大爆发的时代,一个单一的开源数据库产品往往很难直接满足企业的业务需求,在某些场景下,无论是性能、安全还是稳定性,都面临着各种各样的问题。 你在工作中也有这样的烦恼的话,一定是因为你还没有使用过…...
Golang清晰代码指南
发挥易读和易维护软件的好处 - 第一部分 嗨,开发者们,清晰的代码是指编写易于阅读、理解和维护的软件代码。它是遵循一组原则和实践,优先考虑清晰性、简单性和一致性的代码。清晰的代码旨在使代码库更易管理,减少引入错误的可能性…...
C语言 文件I/O(备查)
所有案列 跳转到其他。 文件打开 FILE* fopen(const char *filename, const char *mode); 参数:filename:指定要打开的文件名,需要加上路径(相对、绝对路径)mode:指定文件的打开模式 返回值:成…...
web(HTML之表单练习)
使用HTML实现该界面: 要求如下: 用户名为文本框,名称为 UserName,长度为 15,最大字符数为 20。 密码为密码框,名称为 UserPass,长度为 15,最大字符数为 20。 性别为两个单选按钮&a…...
通过对象轮换实现 LRU 缓存结构
文章目录 通过两个对象轮换,按照是否访问实现内容长久保存rollup 的缓存实现 export default function (max) { //max 缓存容量var num, curr, prev;var limit max || 1;function keep(key, value) {if (num > limit) {prev curr; // 超过容量时当前对象变成缓…...
【Unity动画】综合案例完结-控制角色动作播放+声音配套
这个案例实现的动作并不复杂,主要包含一个 跳跃动作、攻击动作、还有一个包含三个动画状态的动画混合树。然后设置三个参数来控制切换。 状态机结构如下: 完整代码 using System.Collections; using System.Collections.Generic; using UnityEngine;pu…...
【工作流Activiti】任务组
1、Candidate-users候选人 1.1、需求 在流程定义中在任务结点的assignee固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn文件中,如果要临时变更任务负责人则需要修改流程定义,系统扩展性很差,针对这种情况,我…...
桌面概率长按键盘无法连续输入问题
问题描述:概率性长按键盘无法连续输入文本 问题定位: 系统按键流程分析 图一 系统按键流程 按键是由X Server接收的,这一点只要明白了X Window的工作机制就不难理解了。X Server在接收到按键后,会转发到相应程序的窗口中。在窗…...
用23种设计模式打造一个cocos creator的游戏框架----(十九)备忘录模式
1、模式标准 模式名称:备忘录模式 模式分类:行为型 模式意图:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态 结构图: 适用于: …...
动手学深度学习-自然语言处理-预训练
词嵌入模型 将单词映射到实向量的技术称为词嵌入。 为什么独热向量不能表达词之间的相似性? 自监督的word2vec。 word2vec将每个词映射到一个固定长度的向量,这些向量能更好的表达不同词之间的相似性和类比关系。 word2vec分为两类,两类…...
力扣200. 岛屿数量(java DFS解法)
Problem: 200. 岛屿数量 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 该问题可以归纳为一类遍历二维矩阵的题目,此类中的一部分题目可以利用DFS来解决,具体到本题目: 1.我们首先要针对于二维数组上的每一个点,尝试展…...
解决el-table组件中,分页后数据的勾选、回显问题?
问题描述: 1、记录一个弹窗点击确定按钮后,table列表所有勾选的数据信息2、再次打开弹窗,回显勾选所有保存的数据信息3、遇到的bug:切换分页,其他页面勾选的数据丢失;点击确认只保存当前页的数据࿱…...
web网络安全
web安全 一,xss 跨站脚本攻击(全称Cross Site Scripting,为和CSS(层叠样式表)区分,简称为XSS)是指恶意攻击者在Web页面中插入恶意javascript代码(也可能包含html代码),当用户浏览网页之时&…...
若依 ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码
目录 0. 前言0.1 说明 1. 后端部分1.1 添加依赖1.2. 修改 application.yml1.3. 新增 CaptchaRedisService 类1.4. 添加必须文件1.5. 移除不需要的类1.6. 修改登录方法1.7. 新增验证码开关获取接口1.8. 允许匿名访问 2. 前端部分(Vue3)2.1. 新增依赖 cryp…...
安卓10 flutter webview 回退会闪退
现象 在安卓10设备上,访问了webview页面后,回退到其他页面后,大概率会闪退,请查看issuses https://github.com/flutter/flutter/issues/78405 解决思路:在回退前,先把webview销毁掉,重新生成一个…...
【Unity入门】物体5种移动方法
目录 一、通过修改位置来实现移动二、通过物理系统实现位移三、通过CharacterController组件四、通过输入控制物体移动 一、通过修改位置来实现移动 利用修改Transform组件的position的两种常用方法。 使用Translate()函数 /*物体将向x方向移动1.5单位…...
南京做公司网站的公司哪家好/进入百度官网首页
“yes,你看着这鬼代码,竟然在 for 循环里面搞了个 try-catch,不知道try-catch有性能损耗吗?”老陈煞有其事地指着屏幕里的代码: for (int i 0; i < 5000; i) {try {dosth} catch (Exception e) {e.printStackTrace…...
淘宝联盟怎么做自己的网站/推广方案
注意:需要设置ListBox的属性 ScrollViewer.HorizontalScrollBarVisibility"Disabled" 关键代码,WPF中有内置的WrapPanel控件,在ListBox.ItemsPanel中使用可以让元素按块显示 <ListBox.ItemsPanel> <ItemsPanelTemplate> …...
阿里免费做网站/上海百度研发中心
1.1 相对路径和绝对路径 当你执行命令的时,通过PATH 这个变量来找到命令。 首先了解一些路径 PATH : 绝对路径,一定有根目录写起相对路径,不是从根目录写起的。。相对路径意指对于目前工作目录的路径相对路径的意义,…...
建设数据库搜索网站/360收录查询
这是一个练习作品。用python脚本爬取笔趣阁上面的免费小说。 环境:python3类库:BeautifulSoup数据源:http://www.biqukan.cc 原理就是伪装正常http请求,正常访问网页。然后通过bs4重新解析html结构来提取有效数据。 1. config文件…...
网站建设征集通讯员的通知/徐汇网站建设
在WebSocket中添加ssl遇到的问题 [toc] 做个记录 错误日志及解决方案 可以从复制下自己的错误,在网页中找下,看下能不能找到。 // System.setProperty(“javax.net.debug”, “all”); 问题1:javax.net.ssl.SSLHandshakeException: No …...
一个人看片免费高清/网络seo排名
参考资料https://github.com/mattias-ohlsson/gitlab-installer/blob/master/gitlab-install-el6.sh 环境准备OS: CentOS 6.3 x86_64 1.初识GitLabGitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问…...