当前位置: 首页 > news >正文

Spark

Spark

概述

Apache Spark是用于大规模数据处理的统一分析计算引擎

Spark基于内存计算,提高了在大数据环境下数据处理的实时性,同时保证了高容错性和高可伸缩性,允许用户将Spark部署在大量硬件之上,形成集群。

spark与Hadoop的区别

尽管Spark相对于Hadoop而言具有较大优势,但Spark并不能完全替代Hadoop,Spark主要用于替代Hadoop中的MapReduce计算模型。存储依然可以使用HDFS,但是中间结果可以存放在内存中;调度可以使用Spark内置的,也可以使用更成熟的调度系统YARN等

实际上,Spark已经很好地融入了Hadoop生态圈,并成为其中的重要一员,它可以借助于YARN实现资源调度管理,借助于HDFS实现分布式存储。

此外,Hadoop可以使用廉价的、异构的机器来做分布式存储与计算,但是,Spark对硬件的要求稍高一些,对内存与CPU有一定的要求。

特点

  • 与Hadoop的MapReduce相比,Spark基于内存的运算要快100倍以上,基于硬盘的运算也要快10倍以上。Spark实现了高效的DAG执行引擎,可以通过基于内存来高效处理数据流。

  • 易用

    Spark支持Java、Python、R和Scala的API,还支持超过80种高级算法,使用户可以快速构建不同的应用。而且Spark支持交互式的Python和Scala的shell,可以非常方便地在这些shell中使用Spark集群来验证解决问题的方法。

  • 通用

    Spark提供了统一的解决方案。Spark可以用于批处理、交互式查询(Spark SQL)、实时流处理(Spark Streaming)、机器学习(Spark MLlib)和图计算(GraphX)。这些不同类型的处理都可以在同一个应用中无缝使用。Spark统一的解决方案非常具有吸引力,毕竟任何公司都想用统一的平台去处理遇到的问题,减少开发和维护的人力成本和部署平台的物力成本。

  • 兼容性

    Spark可以非常方便地与其他的开源产品进行融合。比如,Spark可以使用Hadoop的YARN和Apache Mesos作为它的资源管理和调度器,并且可以处理所有Hadoop支持的数据,包括HDFS、HBase和Cassandra等。这对于已经部署Hadoop集群的用户特别重要,因为不需要做任何数据迁移就可以使用Spark的强大处理能力。Spark也可以不依赖于第三方的资源管理和调度器,它实现了Standalone作为其内置的资源管理和调度框架,这样进一步降低了Spark的使用门槛,使得所有人都可以非常容易地部署和使用Spark。

运行模式

local本地模式(单机)

(开发测试使用)

分为local单线程和local-cluster多线程

standalone独立集群模式

(开发测试使用)

典型的Mater/slave模式

standalone-HA高可用模式

(生产环境使用)

基于standalone模式,使用zk搭建高可用,避免Master是有单点故障的

on yarn集群模式

(生产环境使用)

运行在 yarn 集群之上,由 yarn 负责资源管理,Spark 负责任务调度和计算,

好处:计算资源按需伸缩,集群利用率高,共享底层存储,避免数据跨集群迁移。

FIFO、Fair、Capacity

on mesos集群模式

(国内使用较少)

运行在 mesos 资源管理器框架之上,由 mesos 负责资源管理,Spark 负责任务调度和计算

on cloud集群模式

(中小公司未来会更多的使用云服务)

比如 AWS 的 EC2,使用这个模式能很方便的访问 Amazon的 S3

spark-submit

./bin/spark-submit \--class <main-class> \--master <master-url> \--deploy-mode <deploy-mode> \--conf <key>=<value> \... # other options<application-jar> \[application-arguments]

以下是一些常用的Spark-submit命令选项以及它们的含义:

  • --class:应用程序入口点的类名,例如 org.apache.spark.examples.SparkPi
  • --master:集群的主节点URL,例如 spark://23.195.26.187:7077
  • --deploy-mode:决定驱动程序运行在哪里,可以是客户端或集群模式,默认为客户端模式 client
  • --conf:以key=value的格式指定 Spark 配置属性,如果值包含空格,需要将整个 ”key=value“ 用双引号引起来。多个配置应该作为单独的参数传递。 (e.g. --conf <key>=<value> --conf <key2>=<value2>)
  • application-jar:包含应用程序和所有依赖项的打包 jar 文件的路径。这个 URL 必须在集群中全局可见,例如一个 hdfs:// 路径或者在所有节点上都存在的 file:// 路径。
  • application-arguments:传递给主类 main 方法的参数列表。例如:arg1 arg2 arg3

例如:

# Run application locally on 8 cores
./bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master local[8] \/path/to/examples.jar \100# Run on a Spark standalone cluster in client deploy mode
./bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master spark://207.184.161.138:7077 \--executor-memory 20G \--total-executor-cores 100 \/path/to/examples.jar \1000# Run on a Spark standalone cluster in cluster deploy mode with supervise
./bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master spark://207.184.161.138:7077 \--deploy-mode cluster \--supervise \--executor-memory 20G \--total-executor-cores 100 \/path/to/examples.jar \1000# Run on a YARN cluster in cluster deploy mode
export HADOOP_CONF_DIR=XXX
./bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master yarn \--deploy-mode cluster \--executor-memory 20G \--num-executors 50 \/path/to/examples.jar \1000# Run a Python application on a Spark standalone cluster
./bin/spark-submit \--master spark://207.184.161.138:7077 \examples/src/main/python/pi.py \1000

手写word count

使用RDD API

import org.apache.spark.{SparkConf, SparkContext}object WordCount {def main(args: Array[String]) {// 创建SparkConf和SparkContext对象val conf: SparkConf = new SparkConf().setAppName("WordCount")val sc: SparkContext = new SparkContext(conf)// 读取文件并进行Word Count//val textFile: RDD[String] = sc.textFile("input.txt")//val words: RDD[String] = textFile.flatMap((line: String) => line.split(" ")) // 将每行文本切分成单词//val pairs: RDD[(String, Int)] = words.map((word: String) => (word, 1)) // 转换成键值对//val counts: RDD[(String, Int)] = pairs.reduceByKey((a: Int, b: Int) => a + b) // 按照键进行聚合val counts = sc.textFile("input.txt").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)// 输出结果到控制台并保存到文本文件counts.collect().foreach(println)counts.saveAsTextFile("output.txt")// 关闭SparkContextsc.stop()}
}

使用DataSet API、DataFrame API:

import org.apache.spark.sql.{Dataset, SparkSession}object WordCount {def main(args: Array[String]): Unit = {val spark: SparkSession = SparkSession.builder.appName("Word Count").getOrCreate()// 使用 DataFrame 进行 Word Countval df: Dataset[(String, Int)] = spark.read.textFile("input.txt").flatMap(_.split(" ")).groupBy("value").count().as[(String, Int)]df.show()df.write.csv("output_df")// 使用 DataSet 进行 Word Countval ds: Dataset[(String, Int)] = spark.read.textFile("input.txt").flatMap(_.split(" ")).groupByKey(_._1).reduceGroups((a, b) => (a._1, a._2 + b._2)).map(_._2)ds.show()ds.write.csv("output_ds")spark.stop()}
}

rdd是什么

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算的集合。

  • Dataset: 它是一个集合,可以存放很多元素

  • Distributed :它里面的元素是分布式存储的,可以用于分布式计算

  • Resilient :它是弹性的,RDD里面的中的数据可以保存在内存中或者磁盘里面

五大属性

一个RDD对象,包含如下5个核心属性。
  1)一个分区列表,每个分区里是RDD的部分数据(或称数据块)。
  2)一个依赖列表,存储依赖的其他RDD。
  3)一个名为compute的计算函数,用于计算RDD各分区的值。
  4)分区器(可选),用于键/值类型的RDD,比如某个RDD是按散列来分区。
  5)计算各分区时优先的位置列表(可选),比如从HDFS上的文件生成RDD时,RDD分区的位置优先选择数据所在的节点,这样可以避免数据移动带来的开销。

创建方式

//由一个已经存在的Scala集合创建
val data = Array(1, 2, 3, 4, 5)
val distData = sc.parallelize(data)//由外部存储系统的数据集创建
val distFile = sc.textFile("data.txt")
//distFile: org.apache.spark.rdd.RDD[String] = data.txt MapPartitionsRDD[10] at textFile at <console>:26

算子

  • Transformation转换操作:返回一个新的RDD

  • Action动作操作:返回值不是RDD(无返回值或返回其他的)

transformation算子

转换含义
map(func)返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成
filter(func)返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成
flatMap(func)类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)
mapPartitions(func)类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]
mapPartitionsWithIndex(func)类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是(Int, Interator[T]) => Iterator[U]
sample(withReplacement, fraction, seed)根据fraction指定的比例对数据进行采样,可以选择是否使用随机数进行替换,seed用于指定随机数生成器种子
union(otherDataset)对源RDD和参数RDD求并集后返回一个新的RDD
intersection(otherDataset)对源RDD和参数RDD求交集后返回一个新的RDD
distinct([numTasks]))对源RDD进行去重后返回一个新的RDD
groupByKey([numTasks])在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD
reduceByKey(func, [numTasks])在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置
aggregateByKey(zeroValue)(seqOp, combOp, [numTasks])当对(K,V)对的数据集进行调用时,使用给定的组合函数和中性“零”值返回一个(K,U)对的数据集,其中每个键的值都被聚合。允许聚合值类型与输入值类型不同,同时避免不必要的分配。与groupByKey一样,通过可选的第二个参数来配置减少任务的数量。
sortByKey([ascending], [numTasks])在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
sortBy(func,[ascending], [numTasks])与sortByKey类似,但是更灵活
join(otherDataset, [numTasks])在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
cogroup(otherDataset, [numTasks])在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD
cartesian(otherDataset)笛卡尔积
pipe(command, [envVars])对rdd进行管道操作
coalesce(numPartitions)减少 RDD 的分区数到指定值。在过滤大量数据之后,可以执行此操作
repartition(numPartitions)重新给 RDD 分区

action算子

动作含义
reduce(func)通过func函数聚集RDD中的所有元素,这个功能必须是可交换且可并联的
collect()在驱动程序中,以数组的形式返回数据集的所有元素
count()返回RDD的元素个数
first()返回RDD的第一个元素(类似于take(1))
take(n)返回一个由数据集的前n个元素组成的数组
takeSample(withReplacement,num, [seed])返回一个数组,该数组由从数据集中随机采样的num个元素组成,可以选择是否用随机数替换不足的部分,seed用于指定随机数生成器种子
takeOrdered(n, [ordering])返回自然顺序或者自定义顺序的前 n 个元素
saveAsTextFile(path)将数据集的元素以textfile的形式保存到HDFS文件系统或者其他支持的文件系统,对于每个元素,Spark将会调用toString方法,将它装换为文件中的文本
saveAsSequenceFile(path)将数据集中的元素以Hadoop sequencefile的格式保存到指定的目录下,可以使HDFS或者其他Hadoop支持的文件系统。
saveAsObjectFile(path)将数据集的元素,以 Java 序列化的方式保存到指定的目录下
countByKey()针对(K,V)类型的RDD,返回一个(K,Int)的map,表示每一个key对应的元素个数。
foreach(func)在数据集的每一个元素上,运行函数func进行更新。
foreachPartition(func)在数据集的每一个分区上,运行函数func

checkpoint

持久化/缓存可以把数据放在内存中,虽然是快速的,但是也是最不可靠的;也可以把数据放在磁盘上,也不是完全可靠的!例如磁盘会损坏等。

Checkpoint的产生就是为了更加可靠的数据持久化,在Checkpoint的时候一般把数据放在在HDFS上,这就天然的借助了HDFS天生的高容错、高可靠来实现数据最大程度上的安全,实现了RDD的容错和高可用。

具体用法:

sc.setCheckpointDir("hdfs://node01:8020/ckpdir") 
//设置检查点目录,会立即在HDFS上创建一个空目录
val rdd1 = sc.textFile("hdfs://node01:8020/wordcount/input/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
rdd1.checkpoint //对rdd1进行检查点保存
rdd1.collect //Action操作才会真正执行checkpoint
//后续如果要使用到rdd1可以从checkpoint中读取

持久化和Checkpoint的区别

  • 位置

​ Persist 和 Cache 只能保存在本地的磁盘和内存中(或者堆外内存–实验中)。

​ Checkpoint 可以保存数据到 HDFS 这类可靠的存储上。

  • 生命周期

​ Cache和Persist的RDD会在程序结束后会被清除或者手动调用unpersist方法。

​ Checkpoint的RDD在程序结束后依然存在,不会被删除。

  • Lineage(血统、依赖链–其实就是依赖关系)

​ Persist和Cache,不会丢掉RDD间的依赖链/依赖关系,因为这种缓存是不可靠的,如果出现了一些错误(例如 Executor 宕机),需要通过回溯依赖链重新计算出来。

​ Checkpoint会斩断依赖链,因为Checkpoint会把结果保存在HDFS这类存储中,更加的安全可靠,一般不需要回溯依赖链。

rdd的依赖关系

窄依赖:父RDD的一个分区只会被子RDD的一个分区依赖

宽依赖:父RDD的一个分区会被子RDD的多个分区依赖(涉及到shuffle)

作用

对于窄依赖:

  • Spark可以并行计算;

  • 如果有一个分区数据丢失,只需要从父RDD的对应1个分区重新计算即可,不需要重新计算整个任务,提高容错。

对于宽依赖:

  • 是划分Stage的依据

rdd的依赖关系

DAG

DAG(Directed Acyclic Graph有向无环图)指的是数据转换执行的过程,有方向,无闭环(其实就是RDD执行的流程)

原始的RDD通过一系列的转换操作就形成了DAG有向无环图,任务执行时,可以按照DAG的描述,执行真正的计算(数据被操作的一个过程)。一个Spark应用中可以有一到多个DAG,取决于触发了多少次Action。

stage的划分

为什么要划分

​ 并行计算

​ 一个复杂的业务逻辑如果有shuffle,那么就意味着前面阶段产生结果后,才能执行下一个阶段,即下一个阶段的计算要依赖上一个阶段的数据。那么我们按照shuffle进行划分(也就是按照宽依赖就行划分),就可以将一个DAG划分成多个Stage/阶段,在同一个Stage中,会有多个算子操作,可以形成一个pipeline流水线,流水线内的多个平行的分区可以并行执行。

如何划分

​ Spark会根据shuffle/宽依赖使用回溯算法来对DAG进行Stage划分,从后往前,遇到宽依赖就断开,遇到窄依赖就把当前的RDD加入到当前的stage/阶段中。

stage的划分

spark程序的运行流程

cluster-overview

构建Spark Application运行环境

/

SparkContext向资源管理器注册

SparkContext向资源管理器申请运行Executor

资源管理器分配Executor

资源管理器启动Executor

Executor发送心跳至资源管理器

/

SparkContext构建成DAG图

将DAG图分解成Stage(TaskSet)

把Stage(TaskSet)发送给TaskScheduler

/

Executor向SparkContext申请Task

TaskScheduler将Task发放给Executor运行

/

Task在Executor上运行,运行完毕释放所有资源

DataFrame 和 DataSet

dataframe

DataFrame的前身是SchemaRDD,不再直接继承自RDD,而是自己实现了RDD的绝大多数功能。

DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库的二维表格,带有Schema元信息(可以理解为数据库的列名和类型)

dataSet

与DataFrame相比,保存了类型信息,是强类型的,提供了编译时类型检查。

DataSet包含了DataFrame的功能,DataFrame=DataSet[Row],即DataSet的子集。

rdd、dataframe和dataset区别

sparkStreaming

Spark Streaming是一个基于Spark Core之上的实时计算框架,可以从很多数据源消费数据并对数据进行实时的处理,具有高吞吐量和容错能力强等特点。

Spark Streaming 提供了一种称为离散流或DStream 的高级抽象,它表示连续的数据流。

在内部,一个 DStream 被表示为一个RDDs序列。

streaming-flow

streaming-dstream-ops

滑动窗口

spark-stream滑动窗口

整合kafka

Receiver接收方式

KafkaUtils.createDstream (不常用)

  • Receiver作为常驻的Task运行在Executor等待数据,但是一个Receiver效率低,需要开启多个,再手动合并数据(union),再进行处理,很麻烦
  • Receiver那台机器挂了,可能会丢失数据,所以需要开启WAL(预写日志)保证数据安全,那么效率又会降低
  • spark在消费的时候为了保证数据不丢也会在Checkpoint中存一份offset,可能会出现数据不一致

Direct直连方式

KafkaUtils.createDirectStream(开发中使用,要求掌握)

  • Direct方式是直接连接kafka分区来获取数据,从每个分区直接读取数据大大提高了并行能力
  • Direct方式调用Kafka低阶API(底层API),offset自己存储和维护,默认由Spark维护在checkpoint中,消除了与zk不一致的情况
  • 当然也可以自己手动维护,把offset存在mysql、redis中
  • 所以基于Direct模式可以在开发中使用,且借助Direct模式的特点+手动操作可以保证数据的Exactly once 精准一次
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribeval kafkaParams = Map[String, Object]("bootstrap.servers" -> "localhost:9092,anotherhost:9092","key.deserializer" -> classOf[StringDeserializer],"value.deserializer" -> classOf[StringDeserializer],"group.id" -> "use_a_separate_group_id_for_each_stream","auto.offset.reset" -> "latest","enable.auto.commit" -> (false: java.lang.Boolean)
)val topics = Array("topicA", "topicB")
val stream = KafkaUtils.createDirectStream[String, String](streamingContext,PreferConsistent,Subscribe[String, String](topics, kafkaParams)
)stream.map(record => (record.key, record.value))

shuffle

HashShuffle

在Map阶段,Mapper任务会根据自己负责的数据块进行计算,并将结果写入磁盘中的本地文件;在Shuffle阶段,Reducer任务会通过网络将Mapper任务产生的partition文件拉取到自己的节点上,然后对相同key的结果进行合并,形成最终结果。

Sort Shuffle

在Map阶段将输出结果按照key排序,然后在Shuffle阶段只传输每个Reducer所需的数据,减少了数据复制和网络通信的开销。

Bypass机制

在Map Task中自行进行分区和排序,跳过Reducer阶段的shuffle处理,从而避免了大量的磁盘I/O和网络I/O操作。

Repartition 和 Coalesce

关系: 两者都是用来改变 RDD 的 partition 数量的,repartition 底层调用的就是 coalesce 方 法。

区别: repartition 一定会发生 shuffle,coalesce 根据传入的参数来判断是否发生 shuffle 。

​ 一般情况下增大 rdd 的 partition 数量使用 repartition,减少 partition 数量时使用 coalesce。

调优

基础调优

  • 资源配置

    Spark应用程序的性能受到内存、CPU、磁盘I/O等因素的影响。应根据集群硬件配置的情况,合理分配每个执行器(Executor)的内存大小和CPU核数,避免过度分配或低效利用资源。

  • 并行度设置

    并行度越高,Spark处理数据的速度就越快。可以通过调整RDD的分区数量、设置并发任务数和线程数等方式来增加并行度,同时要避免过度调整造成资源浪费。官方推荐,task数量应该设置为Spark作业总CPU core数量的2~3倍。

  • 序列化选择

    可以使用Java序列化或Kryo序列化库。Kryo性能更好,但不支持所有的对象,spark默认是Java序列化。

  • 缓存和checkpoint:

    缓存经常被读取和重用的数据可以有效提高性能,减少计算时间和网络带宽的消耗。在缓存数据时,应注意内存限制和缓存数据更新的策略。使用checkpoint的优点在于提高了Spark作业的可靠性,一旦缓存出现问题,不需要重新计算数据,缺点在于,checkpoint时需要将数据写入HDFS等文件系统,对性能的消耗较大。

  • 广播变量

    避免某些占空间大的变量随副本在集群中复制。

算子调优

  • 优化rdd计算逻辑流程,避免重复计算

  • 尽早的filter

  • filter+coalesce减少分区,因为filter后数据变少,资源浪费

  • reducebykey本地预聚合

    groupByKey只有reduce端聚合

    reduceByKey可以map端预聚合

  • foreachpartition

    rrd.foreache(_…)//_表示每一个元素

    rrd.forPartitions(_…)//_表示每个分区的数据组成的迭代器

    foreachPartition是将RDD的每个分区作为遍历对象,一次处理一个分区的数据,也就是说,如果涉及数据库的相关操作,一个分区的数据只需要创建一次数据库连接。

shuffle调优

  • 调整map和reduce端缓冲区大小

  • 调整reduce端重试次数和等待时间间隔

    数据较大或者网络不佳时,可以调大这两个参数

  • bypass机制开启阈值

数据倾斜

  • 提前过滤可能导致数据倾斜的key对应的数据
  • 使用随机key
  • 提高reduce并行度
  • 使用map join,广播小RDD全量数据+map算子

相关文章:

Spark

Spark 概述 Apache Spark是用于大规模数据处理的统一分析计算引擎 Spark基于内存计算&#xff0c;提高了在大数据环境下数据处理的实时性&#xff0c;同时保证了高容错性和高可伸缩性&#xff0c;允许用户将Spark部署在大量硬件之上&#xff0c;形成集群。 spark与Hadoop的…...

poi生成excel饼图设置颜色

效果 实现 import com.gideon.entity.ChartPosition; import com.gideon.entity.LineChart; import com.gideon.entity.PieChart; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xddf.usermodel.PresetColo…...

多版本管理node.js

多版本管理node.js 1. 安装2. 配置使用2.1 修改node源2.2 常用命令 在Windows 计算机上管理node.js的多个安装版本。 这是朋友推荐的&#xff0c;就是自己在升级node的时候给搞崩了&#xff0c; 不得不提升效率&#xff0c;于是发现了这个好工具&#xff0c;可以反过来理解&…...

【深入浅出 Spring Security(七)】RememberMe的实现原理详讲

RememberMe 的实现原理 一、RememberMe 的基本使用二、RememberMeAuthenticationFilter 源码分析RememberMeServicesTokenBasedRememberMeServicesTokenBasedRememberMeServices 中对 processAutoLoginCookie 方法的实现总结原理图式 三、提高安全性PersistentTokenBasedRememb…...

Cesium 实战 - 使用 gltf-vscode 查看、预览以及编辑 glTF 和 GLB 模型

Cesium 实战 - 使用 gltf-vscode 查看、预览以及编辑 glTF 和 GLB 模型 VScode&#xff08;Visual Studio Code&#xff09; 安装模型必要插件VScode 预览自定义关节&#xff08;articulations&#xff09;动作VScode 导入 GLB 格式模型VScode 导出 GLB 格式模型 模型渲染作为 …...

Python自动化测试框架:Pytest和Unittest的区别

pytest和unittest是Python中常用的两种测试框架&#xff0c;它们都可以用来编写和执行测试用例&#xff0c;但两者在很多方面都有所不同。本文将从不同的角度来论述这些区别&#xff0c;以帮助大家更好地理解pytest和unittest。 1. 原理 pytest是基于Python的assert语句和Pytho…...

考研算法29天:希尔排序 【希尔排序】

算法介绍 希尔排序 等差数列 普通版插入排序 循环数组 第一次每n/2为间隔分为4组&#xff0c;然后组内排序。 第二次每n/4为间隔分为2组。然后组内排序 第三次n/8为间隔分为一组。然后组内排序。 组内排序用插入排序来排序。 注&#xff1a;也可以第一次为n/3为间隔&am…...

RN 学习小记之使用 Expo 创建项目

本文Hexo博客链接&#x1f517; https://ysx.cosine.ren/react-native-note-1 xLog链接&#x1f517; https://x.cosine.ren/react-native-note-1 RSS订阅 &#x1f4e2; https://x.cosine.ren/feed/xml 由于业务需要&#xff0c;开始学习RN以备后面的需求&#xff0c;而虽然之…...

python爬虫从入门到精通

目录 一、正确认识Python爬虫 二、了解爬虫的本质 1. 熟悉Python编程 2. 了解HTML 3. 了解网络爬虫的基本原理 4. 学习使用Python爬虫库 三、了解非结构化数据的存储 1. 本地文件 2. 数据库 四、掌握各种技巧&#xff0c;应对特殊网站的反爬措施 1. User-Agent 2. C…...

从0到1精通自动化,接口自动化测试——数据驱动DDT实战

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 DDT简介 名称&am…...

【微服务】springboot整合swagger多种模式使用详解

目录 一、前言 1.1 编写API文档 1.2 使用一些在线调试工具 1.3 postman 1.4 swagger 二、swagger简介</...

AI 绘画(1):生成一个图片的标准流程

文章目录 文章回顾感谢人员生成一个图片的标准流程前期准备&#xff0c;以文生图为例去C站下载你需要的绘画模型导入参数导入生成结果&#xff1f;可能是BUG事后处理 图生图如何高度贴合原图火柴人转角色 涂鸦局部重绘 Ai绘画公约 文章回顾 AI 绘画&#xff08;0&#xff09;&…...

CPU、内存、缓存的关系

术语解释 &#xff08;1&#xff09;CPU&#xff08;Central Processing Unit&#xff09; 中央处理器 &#xff08;2&#xff09;内存 内存用于暂时存放CPU中的运算数据&#xff0c;以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁&#xff0c;内存的运行决定…...

AI黑客松近期比赛清单;36氪AI淘宝店盈利复盘;GitHub Copilot官方最佳实践;AI在HR领域的应用探索 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; ⋙ 点击查看 AI Hackathon (黑客马拉松) 汇总清单 &#x1f916; 〖飞桨〗2023大模型应用创新挑战赛 百度飞桨联合上海市青年五十人创新创业研究院等…...

想要让视频素材格式快速调整转换的方法分享

有时候有些视频播放软件不支持播放某些格式的视频文件&#xff1f;那要怎么解决呢&#xff1f;换一个播放软件&#xff1f;不妨试试批量转换视频格式&#xff0c;简单的几步操作就能快速解决烦恼&#xff0c;跟着小编一起来看看具体的操作环节吧。 首先先进入“固乔科技”的官网…...

面向对象分析与设计 UML2.0 学习笔记

一、认识UML UML-Unified Modeling Language 统一建模语言&#xff0c;又称标准建模语言。是用来对软件密集系统进行可视化建模的一种语言。UML的定义包括UML语义和UML表示法两个元素。 UML是在开发阶段&#xff0c;说明、可视化、构建和书写一个面向对象软件密集系统的制品的…...

[数据库系统] 五、数据增删改

第一关&#xff1a;数据插入 用insert给数据库添加数据 相关知识 有关系student(sno,sname,ssex,sage,sdept)&#xff0c;属性对应含义&#xff1a;学号&#xff0c;姓名&#xff0c;性别&#xff0c;所在系。现有的部分元组如下所示 insert 向数据库表插入数据的基本格式有…...

docker私有注册表创建和使用

说明 本文给出了一个具体的使用docker registry和nginx配置docker私有注册表的方案。 创建和配置 docker compose 使用docker compose的方式运行registry容器&#xff0c;配置如下&#xff1a; # cat docker-compose.yml services:registry:image: registry:2ports:- &quo…...

用OpenCV进行OCR字符分割

1. 引言 本文重点介绍如何利用传统的图像处理的方法来进行OCR字符切分&#xff0c;进而可以用分割后的单个字符做相应的后续任务&#xff0c;虽然现在计算机视觉依然是卷积神经网络的天下&#xff0c;但是对于一些相对简单的落地场景传统方案还是很有效的。 闲话少说&#xff…...

MyCat Docker 搭建与测试

mycat 是mysql分库分表的中间件&#xff0c;由java编写&#xff0c;本次进行mysql、mycat 的docker搭建&#xff0c;理解mycat的原理与特性。 一、mysql docker 搭建 这里启动两个实例&#xff1a; docker run -itd --name mysql1 -p 3307:3306 -e MYSQL_ROOT_PASSWORD123 m…...

车载通讯USB开发,增强车内娱乐体验

车载通讯开发中使用的 USB 协议常见于车内娱乐系统、车载设备和汽车诊断工具等应用。USB&#xff08;Universal Serial Bus&#xff0c;通用串行总线&#xff09;是一种常见的数字通信接口标准&#xff0c;用于连接计算机、外部设备及其他电子设备之间的数据传输和通信。 USB …...

js的一些小技巧

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 作用域 全局作用域局部作用域&#xff08;函数里&#xff09;也称函数作用域块级作用域 {…...

Springboot Mybatis 自定义顺序排序查询,指定某个字段

前言 与本文无关 "我进去了" ....... 正文 今天要讲些什么&#xff1f; 其实很简单&#xff0c;就是查询数据的时候&#xff0c;想根据自己指定的字段的自定义顺序&#xff0c;做排序查询数据。 本篇文章会讲到的几个点 &#xff1a; 1. 单纯sql 怎么实现 排序2. …...

期刊会议审稿意见

AAAI 修改意见 违背了研究方向的假设&#xff1b;虽然实验结果不错&#xff0c;但是没有明确地指向任何成功的方向&#xff0c;作者也没有充分地处理失败的案例——The results, though good are not clearly pointing to any direction of success, and the authors have no…...

Java类加载机制:从字节码到对象的奇妙之旅

目录 什么是类加载机制&#xff1f; 类加载顺序 类加载顺序图 双亲委派模型 双亲委派模型示意图 如何打破双亲委派模型&#xff1f; 要想学好java&#xff0c;首先得知道它是什么&#xff0c;怎么运行的&#xff0c;怎么加载的&#xff0c;运行的是个什么东西&#xff0c…...

代码随想录第一天|二分法、双指针

代码随想录第一天 Leetcode 704 二分查找Leetcode 35 搜索插入位置Leetcode 34 在排序数组中查找元素的第一个和最后一个位置Leetcode 69 x 的平方根Leetcode 367 有效的完全平方数Leetcode 27 移除元素Leetcode 26 删除有序数组中的重复项Leetcode 283 移动零Leetcode 844 比较…...

Flink中KeyedStateStore实现--怎么做到一个Key对应一个State

背景 在Flink中有两种基本的状态&#xff1a;Keyed State和Operator State&#xff0c;Operator State很好理解&#xff0c;一个特定的Operator算子共享同一个state&#xff0c;这是实现层面很好做到的。 但是 Keyed State 是怎么实现的&#xff1f;一般来说&#xff0c;正常的…...

flex: 0 0 100%;

flex: 0 0 100%; flex: 0 0 100%; 是一个用于设置flex项的flex-grow、flex-shrink和flex-basis属性的缩写flex-grow&#xff1a;指定了flex项在剩余空间中的放大比例&#xff0c;默认为0&#xff0c;表示不放大。在这个例子中&#xff0c;设置为0表示不允许flex项在水平方向上…...

IMX6ULL系统移植篇-镜像烧写方法

一. 烧录镜像简介 本文我们就来学习&#xff1a;windows 系统下烧录镜像的方法。 如何使用 NXP 官方提供的 MfgTool 工具通过 USB OTG 口来 烧写系统。 二. windows下烧录镜像 1. 烧录镜像前准备工作 &#xff08;1&#xff09;从开发板上拔下 SD卡。 &#xff08;2…...

【Android】实现雷达扫描效果,使用自定义View来绘制雷达扫描动画

要在Android上实现雷达扫描效果&#xff0c;你可以使用自定义View来绘制雷达扫描动画。以下是一个简单的示例代码&#xff1a; 创建一个名为RadarView的自定义View类&#xff0c;继承自View&#xff1a; import android.content.Context; import android.graphics.Canvas; im…...