【Spark源码分析】基于Spark3.4.2源码分析SparkSQL执行过程
基于Spark3.4.2源码分析SparkSQL执行过程
文章目录
- 基于Spark3.4.2源码分析SparkSQL执行过程
- 基本执行流程
- Unresolved逻辑计划树相关类
- RuleExector相关类
- 详细代码
- SparkSession
- AbstractSqlParser
- Dataset
- QueryExecution
- Analyzer
- RuleExecutor
- CheckAnalysis
- 附录
- CTE简述
- SQL解析器
- QueryPlanningTracker
- 类的主要函数
- QueryExecution转化语法树过程
- 注解
- 配置项
- spark.sql.planChangeLog.level
基本执行流程
Spark SQL运行架构简图
- 将SQL语句解析成未绑定的逻辑计划(未解决的关系Relation、函数Function、属性Attribute)
- 配合元数据信息,完善未绑定的逻辑计划的属性转换成绑定的逻辑计划,将元数据信息与catalog绑定。
- 使用优化规则生成优化逻辑计划
- 将优化的逻辑计划转换成可执行的物理计划
- 使用preparations规则进行预处理后,使用SparkPlan的execute执行rdd
Spark SQL四大执行阶段简图
Unresolved逻辑计划树相关类
RuleExector相关类
解析语法树绑定,使用rule绑定逻辑计划
-
在SparkSession中创建SessionState实例对象
-
使用SessionState中的转换接口,调用
AbstractSqlParser.parsePlan
, -
基于基础 SQL 解析基础架构,使用到了ANTLR4进行此法解析。使用由插件分别生成词法解析器
SqlBaseLexer
和语法解析器SqlBaseParser
,尝试使用Antlr4最快解析模式PredictionMode.SLL
解析后,解析失败会在使用PredictionMode.LL
模式解析,对解析结果进行函数柯理化。将sql的内容先由词法解析器解析成token序列,传入语法解析器解析。 -
使用Visitor模式进行遍历,参照SqlBase.g4的语法树进行匹配,产生逻辑计划(未绑定)。
UnresolvedRelation
语法树。 -
构建QueryExecution,通过查询执行器将Unresolved LogicalPlan一路变成costmodel。
以
select * from people
语句为例,其转化过程如下:== Parsed Logical Plan == 'Project [*] +- 'UnresolvedRelation [global_temp, people], [], false== Analyzed Logical Plan == age: bigint, name: string Project [age#8L, name#9] +- SubqueryAlias global_temp.people+- View (`global_temp`.`people`, [age#8L,name#9])+- Relation [age#8L,name#9] json== Optimized Logical Plan == Relation [age#8L,name#9] json== Physical Plan == FileScan json [age#8L,name#9] Batched: false, DataFilters: [], Format: JSON, Location: InMemoryFileIndex(1 paths)[file:/D:/code/spark/spark-3.4.2/examples/src/main/resources/people.json], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<age:bigint,name:string>
-
由RuleExcutor.execute(plan),按照batches顺序和Batch内的rules顺序,对传入的树节点节点应用对应规则。转换成为完全类型的对象。
详细代码
spark.sql("SELECT * FROM global_temp.people").show();
SparkSession
@Experimentaldef sql(sqlText: String, args: Map[String, Any]): DataFrame = withActive {// 查询计划追踪器val tracker = new QueryPlanningTrackerval plan = tracker.measurePhase(QueryPlanningTracker.PARSING) {// 解析计划--AbstractSqlParser来实现val parsedPlan = sessionState.sqlParser.parsePlan(sqlText)if (args.nonEmpty) {ParameterizedQuery(parsedPlan, args.mapValues(lit(_).expr).toMap)} else {parsedPlan}}// 将执行结果以DataFrame返回Dataset.ofRows(self, plan, tracker)}private[sql] def withActive[T](block: => T): T = {// 直接使用线程本地的活跃会话,以确保我们得到的会话实际上是事实上设置的而不是默认的会话。// 这是为了防止一旦我们都搞完之后把默认会话升级到了活跃会话。val old = SparkSession.activeThreadSession.get()SparkSession.setActiveSession(this)try block finally {SparkSession.setActiveSession(old)}}
AbstractSqlParser
/** 为sql字符串创建逻辑计划 */override def parsePlan(sqlText: String): LogicalPlan = parse(sqlText) { parser =>val ctx = parser.singleStatement()withOrigin(ctx, Some(sqlText)) {// 获取构造器AstBuilder,将ParseTree转换为AST(visit模式)astBuilder.visitSingleStatement(ctx) match {case plan: LogicalPlan => plancase _ =>val position = Origin(None, None)throw QueryParsingErrors.sqlStatementUnsupportedError(sqlText, position)}}}protected def astBuilder: AstBuilderprotected def parse[T](command: String)(toResult: SqlBaseParser => T): T = {logDebug(s"Parsing command: $command")// 将sql内容转换成字符流,并且转换成大写形式。 词法解析器val lexer = new SqlBaseLexer(new UpperCaseCharStream(CharStreams.fromString(command)))// 清空识别错误的监听器lexer.removeErrorListeners()// ParseErrorListener将解析错误转换为 AnalysisException。 ParseException继承AnalysisExceptionlexer.addErrorListener(ParseErrorListener)// 使用指定的令牌源和默认令牌通道 构造一个新的 CommonTokenStreamval tokenStream = new CommonTokenStream(lexer)// SqlBaseParser进行语法解析val parser = new SqlBaseParser(tokenStream)// 语法解析器的后置处理监听器 专门用来验证并清理解析树parser.addParseListener(PostProcessor)// 语法解析器的后置处理监听器用来检查未闭合括号的注释的parser.addParseListener(UnclosedCommentProcessor(command, tokenStream))// 清空错误处理监听器parser.removeErrorListeners()// 添加自定义的编译错误监听器parser.addErrorListener(ParseErrorListener)// 错误处理器SparkParserErrorStrategyparser.setErrorHandler(new SparkParserErrorStrategy())// 配置项spark.sql.legacy.setopsPrecedence.enabled,默认false。// 控制解析计算顺序,顺序未指定时,true时,将按照查询中出现的顺序从左到右执行集合操作。// false时,INTERSECT操作将在任何UNION、EXCEPT和MINUS操作之前执行。parser.legacy_setops_precedence_enabled = conf.setOpsPrecedenceEnforced// 配置项 spark.sql.legacy.exponentLiteralAsDecimal.enabled,默认false// 控制指数数字的转换类型。为true时,带有指数的字面值(例如1E-30)将被解析为Decimal而不是Double。parser.legacy_exponent_literal_as_decimal_enabled = conf.exponentLiteralAsDecimalEnabled// 配置项spark.sql.ansi.enforceReservedKeywords,默认值false。// spark.sql.ansi.enabled ,若SPARK_ANSI_SQL_MODE为true则开启。 v3.0.0// 当true和ANSI_ENABLED为true时,Spark SQL解析器强制使用ANSI保留关键字,并禁止使用保留关键字作为表、视图、函数等的别名和/或标识符的SQL查询。parser.SQL_standard_keyword_behavior = conf.enforceReservedKeywords// 配置项 spark.sql.ansi.doubleQuotedIdentifiers,默认值false。// 当为true且ANSI_ENABLED为true时,Spark SQL读取用双引号(\")括起来的字面值作为标识符。当为false时,它们被读取为字符串字面值。parser.double_quoted_identifiers = conf.doubleQuotedIdentifierstry {try {// 首次解析,使用快速模式SSL模式parser.getInterpreter.setPredictionMode(PredictionMode.SLL)toResult(parser)}catch {case e: ParseCancellationException =>tokenStream.seek(0) // 重置输入流 准备重试parser.reset()//SLL模式解析失败,则转为LL模式再次尝试解析parser.getInterpreter.setPredictionMode(PredictionMode.LL)toResult(parser)}}catch {case e: ParseException if e.command.isDefined =>throw ecase e: ParseException =>throw e.withCommand(command)case e: AnalysisException =>val position = Origin(e.line, e.startPosition)throw new ParseException(Option(command), e.message, position, position,e.errorClass, e.messageParameters)}}
}
Dataset
/** ofRows的一种变体,它允许传入跟踪器,这样我们就可以跟踪查询解析时间。 */def ofRows(sparkSession: SparkSession, logicalPlan: LogicalPlan, tracker: QueryPlanningTracker): DataFrame = sparkSession.withActive {// 使用sparksession,逻辑计划,跟踪器,构建查询查询执行val qe = new QueryExecution(sparkSession, logicalPlan, tracker)// 断言式分析,进行逻辑计划的分析执行qe.assertAnalyzed()// 构建一个新的Datasetnew Dataset[Row](qe, RowEncoder(qe.analyzed.schema))}
QueryExecution
def assertAnalyzed(): Unit = analyzedlazy val analyzed: LogicalPlan = executePhase(QueryPlanningTracker.ANALYSIS) {// We can't clone `logical` here, which will reset the `_analyzed` flag.sparkSession.sessionState.analyzer.executeAndCheck(logical, tracker)}
Analyzer
def executeAndCheck(plan: LogicalPlan, tracker: QueryPlanningTracker): LogicalPlan = {if (plan.analyzed) return planAnalysisHelper.markInAnalyzer {val analyzed = executeAndTrack(plan, tracker)try {// 检查是否可以正常分析,若不行,则异常抛出checkAnalysis(analyzed)analyzed} catch {case e: AnalysisException =>val ae = e.copy(plan = Option(analyzed))ae.setStackTrace(e.getStackTrace)throw ae}}}
RuleExecutor
/*** 执行由子类定义的规则批次,并使用提供的跟踪器跟踪每个规则的计时信息。 跳转到Analyzer.execute方法,最后又跳转到RuleExecutor.execute方法*/def executeAndTrack(plan: TreeType, tracker: QueryPlanningTracker): TreeType = {QueryPlanningTracker.withTracker(tracker) {execute(plan)}}/*** 执行由子类定义的规则批次。批处理使用定义的执行策略连续执行。在每个批处理中,规则也是连续执行的。Analyzer中的batches: Seq[Batch]*/def execute(plan: TreeType): TreeType = {var curPlan = planval queryExecutionMetrics = RuleExecutor.queryExecutionMeterval planChangeLogger = new PlanChangeLogger[TreeType]()val tracker: Option[QueryPlanningTracker] = QueryPlanningTracker.getval beforeMetrics = RuleExecutor.getCurrentMetrics()val enableValidation = SQLConf.get.getConf(SQLConf.PLAN_CHANGE_VALIDATION)// 验证初始输入plan。if (Utils.isTesting || enableValidation) {validatePlanChanges(plan, plan) match {case Some(msg) =>val ruleExecutorName = this.getClass.getName.stripSuffix("$")throw new SparkException(errorClass = "PLAN_VALIDATION_FAILED_RULE_EXECUTOR",messageParameters = Map("ruleExecutor" -> ruleExecutorName, "reason" -> msg),cause = null)case _ =>}}batches.foreach { batch =>val batchStartPlan = curPlanvar iteration = 1var lastPlan = curPlanvar continue = true// 运行直到固定点(或策略中指定的最大迭代次数)。while (continue) {curPlan = batch.rules.foldLeft(curPlan) {case (plan, rule) =>val startTime = System.nanoTime()val result = rule(plan)val runTime = System.nanoTime() - startTimeval effective = !result.fastEquals(plan)if (effective) {queryExecutionMetrics.incNumEffectiveExecution(rule.ruleName)queryExecutionMetrics.incTimeEffectiveExecutionBy(rule.ruleName, runTime)planChangeLogger.logRule(rule.ruleName, plan, result)//在每个规则之后运行计划更改验证。if (Utils.isTesting || enableValidation) {validatePlanChanges(plan, result) match {case Some(msg) =>throw new SparkException(errorClass = "PLAN_VALIDATION_FAILED_RULE_IN_BATCH",messageParameters = Map("rule" -> rule.ruleName,"batch" -> batch.name,"reason" -> msg),cause = null)case _ =>}}}queryExecutionMetrics.incExecutionTimeBy(rule.ruleName, runTime)queryExecutionMetrics.incNumExecution(rule.ruleName)// 使用QueryPlanningTracker记录计时信息tracker.foreach(_.recordRuleInvocation(rule.ruleName, runTime, effective))result}iteration += 1if (iteration > batch.strategy.maxIterations) {// 只有当这条规则应该运行不止一次时才记录日志。if (iteration != 2) {val endingMsg = if (batch.strategy.maxIterationsSetting == null) {"."} else {s", please set '${batch.strategy.maxIterationsSetting}' to a larger value."}val message = s"Max iterations (${iteration - 1}) reached for batch ${batch.name}" +s"$endingMsg"if (Utils.isTesting || batch.strategy.errorOnExceed) {throw new RuntimeException(message)} else {logWarning(message)}}// 检查一次批次的幂等性if (batch.strategy == Once &&Utils.isTesting && !excludedOnceBatches.contains(batch.name)) {checkBatchIdempotence(batch, curPlan)}continue = false}if (curPlan.fastEquals(lastPlan)) {logTrace(s"Fixed point reached for batch ${batch.name} after ${iteration - 1} iterations.")continue = false}lastPlan = curPlan}planChangeLogger.logBatch(batch.name, batchStartPlan, curPlan)}planChangeLogger.logMetrics(RuleExecutor.getCurrentMetrics() - beforeMetrics)curPlan}
CheckAnalysis
def checkAnalysis(plan: LogicalPlan): Unit = {// 内联查询计划中的所有CTE(Common Table Expressions,公用表表达式)val inlineCTE = InlineCTE(alwaysInline = true)val cteMap = mutable.HashMap.empty[Long, (CTERelationDef, Int)]inlineCTE.buildCTEMap(plan, cteMap)cteMap.values.foreach { case (relation, refCount) =>// 如果从未使用过CTE关系,它将在inline之后消失。这里我们显式地检查它的分析,以确保整个查询计划是有效的。if (refCount == 0) checkAnalysis0(relation.child)}// 内联计划中的所有cte,以帮助检查子查询中的查询计划结构。checkAnalysis0(inlineCTE(plan))// 递归地将此计划树中的所有节点标记为已分析plan.setAnalyzed()}
new Dataset[Row](qe, RowEncoder(qe.analyzed.schema))
,其中RowEncoder
用于构造将外部行与Spark SQL内部二进制表示进行转换的编码器。
附录
CTE简述
SQL解析器
在SparkSQL中词法解析器SqlBaseLexer和语法解析器SqlBaseParser,遍历节点有两种模式Listener和Visitor。
Listener模式是被动式遍历,antlr生成类ParseTreeListener,这个类里面包含了所有进入语法树中每个节点和退出每个节点时要进行的操作。我们只需要实现我们需要的节点事件逻辑代码即可,再实例化一个遍历类ParseTreeWalker,antlr会自上而下的遍历所有节点,以完成我们的逻辑处理。
Visitor则是主动遍历模式,需要我们显示的控制遍历的顺序。该模式可以实现在不改变各元素的类的前提下定义作用于这些元素的新操作。SparkSql用的就是此方式来遍历节点的。
QueryPlanningTracker
查询计划执行跟踪器
跟踪计划中阶段运行时间和相关统计信息的简单工具
- 阶段:这些是查询规划中的广泛阶段,如下所示,即analysis、optimization和physical planning(只是规划)。
- 规则:这些是我们跟踪的单个Catalyst规则。除执行耗时外,我们还跟踪调用次数和有效调用次数。
类的主要函数
特质类ParserInterface
中主要方法
- 解析成逻辑计划
- 解析成表达式
- 解析成表标识符
- 解析成函数标识符
- 解析成多分区标识符
- 解析成表schema
- 解析成数据类型
- 将查询语句解析成逻辑计划
接口类ParseTreeVisitor
中的主要访问解析树的方法
- 访问解析树,并返回用户定义的操作结果。
- 访问节点的子节点,并返回用户自定义的操作结果。
- 访问叶子节点,并返回用户自定义的操作结果。
- 访问错误节点,并返回用户自定义的操作结果。
QueryExecution转化语法树过程
阶段输出
== Parsed Logical Plan ==
:构造QueryExecution时候传入的LogicalPlan,即AST(语法抽象树),也为Unresolved Logical Plan== Analyzed Logical Plan ==
:是通过QueryExecution#analyzed进行处理后得到的结果== Optimized Logical Plan ==
:优化逻辑计划== Physical Plan ==
:转换成物理计划
注解
-
@Experimental
面向用户的实验性 API。实验性 API 可能会在 Spark 的次要版本中更改或移除,或被采用为第一类的 Spark API。
注意:如果在此注释之前有 Scaladoc 注释,则注释的第一行必须是":: 实验:::",不留尾部空行。这是因为一个已知的问题,即 Scaladoc 只显示注释或注释,以先显示者为准
配置项
spark.sql.planChangeLog.level
配置日志级别,用于在应用规则或批处理后记录从原始计划到新计划的更改。取值为trace
、debug
、info
、warn
、error
。默认的日志级别是trace
。
相关文章:
【Spark源码分析】基于Spark3.4.2源码分析SparkSQL执行过程
基于Spark3.4.2源码分析SparkSQL执行过程 文章目录 基于Spark3.4.2源码分析SparkSQL执行过程基本执行流程Unresolved逻辑计划树相关类RuleExector相关类 详细代码SparkSessionAbstractSqlParserDatasetQueryExecutionAnalyzerRuleExecutorCheckAnalysis 附录CTE简述SQL解析器Qu…...
centos8:Could not resolve host: mirrorlist.centos.org
【1】错误消息: [rootcentos211 redis-7.0.15]# yum update CentOS Stream 8 - AppStream …...
超详细ensp配置VRRP和MSTP协议
一、简介 1、什么是VRRP: (1)VRRP(Virtual Router Redundancy Protocol)的概念: VRRP(Virtual Router Redundancy Protocol)指的是一种实现路由器冗余备份的协议,常用于…...
聊聊Flink:这次把Flink的触发器(Trigger)、移除器(Evictor)讲透
一、触发器(Trigger) Trigger 决定了一个窗口(由 window assigner 定义)何时可以被 window function 处理。 每个 WindowAssigner 都有一个默认的 Trigger。 如果默认 trigger 无法满足你的需要,你可以在 trigger(…) 调用中指定自定义的 tr…...
为啥不推荐使用数据库外键
为啥不推荐使用数据库外键 前言 在阿里开发手册中写道:不得使用外键与级联,一切外键概念必须在应用层解决。 说明:(概念解释)学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更…...
C# 13 中的新增功能
C# 12 中的新增功能C# 11 中的新增功能C# 10 中的新增功能C# 9.0 中的新增功能C# 8.0 中的新增功能C#7.0中有哪些新特性?C#6.0中10大新特性的应用和总结C# 5.0五大新特性 将C#语言版本升级为预览版 C# 13 包括一些新增功能。 可以使用最新的 Visual Stu…...
sunshine+moonlight
参考自 b站视频 电脑端(发送端) 去 sunshine github 下载 https://github.com/LizardByte/Sunshine/releases/tag/v2024.1127.551下载后打开,创建用户名和密码修改配置选项,启用 UPnP,IP 地址族使用 IPv4IPv6 平板端…...
Python练习题合集
目录 一. 请编程输出其中 “超过平均身高” 的那些值。 二. 字典处理: 三. 求斐波那契数列的前若干项 四. 编程输出最长字符串的长度。 五. 去掉一个最高分,去掉一个最低分,其余分求平均作为最终分数。 六. 打印小九九乘法表 七.…...
frp 内网穿透
文章目录 前言使用自己的服务器搭建frp 这里服务器是linux centos 7 宝塔,client是 windows10 https://github.com/fatedier/frp/releases/tag/v0.53.2 版本下载分客户端与服务端 一、frp是什么?二、使用步骤1.部署服务器端2.客户端 前言 使用自己的服务…...
Vue3 子路由vue如何调用父路由vue中的方法?
1. router -> index.ts 文件: import { createRouter, createWebHistory } from vue-router import DefaultView from /views/default/index.vue import ParentView from /views/parent/index.vue import ChildView from /views/child/index.vueconst router …...
Docker 清理镜像策略详解
文章目录 前言一、删除 Docker 镜像1. 查看当前镜像2. 删除单个镜像3. 删除多个镜像4. 删除所有未使用的镜像5. 删除悬空的 Docker 镜像6. 根据模式删除镜像7. 删除所有镜像 二、删除 Docker 容器1. 查找容器2. 删除一个或多个特定容器3. 退出时删除容器4. 删除所有已退出的容器…...
Qt自定义 Qt Designer 插件
创建 Qt Designer 插件项目 Qt 提供两种设计插件的 API,可以用于扩展 Qt 的功能。高级 API 用于设计插件以扩展 Qt 的功能,例如定制数据库驱动、图像格式、文本编码、定制样式等。Qt Designer 里大量采用了插件,点击 Qt Creator 的“Help”-…...
【C语言】扫雷游戏(一)
我们先设计一个简单的9*9棋盘并有10个雷的扫雷游戏。 1,可以用数组存放,如果有雷就用1表示,没雷就用0表示。 2,排查(2,5)这个坐标时,我们访问周围的⼀圈8个位置黄色统计周围雷的个数是1。排查(8,6)这个坐标时…...
ESP32-S3模组上跑通ES8388(12)
接前一篇文章:ESP32-S3模组上跑通ES8388(11) 二、利用ESP-ADF操作ES8388 2. 详细解析 上一回解析了es8388_init函数中的第5段代码,本回继续往下解析。为了便于理解和回顾,再次贴出es8388_init函数源码,在…...
数据集-目标检测系列- 海边漫步锻炼人检测数据集 person >> DataBall
数据集-目标检测系列- 海边漫步锻炼人检测数据集 person >> DataBall DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 需要更多数据资源和技术解决方案,知识星球: “DataBall - X 数据球…...
【论文笔记】A Token-level Contrastive Framework for Sign Language Translation
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: A Token-level Contrastiv…...
多线程篇-9--锁的使用及分类(可重入锁,读写锁,锁降级,死锁,LockSupport,乐观锁,悲观锁,分段锁等)
1、锁的概述 Java 中,锁是一种用于控制多线程并发访问共享资源的机制。合理的锁机制可以确保线程安全,避免数据竞争和不一致的问题。 Java 提供了多种锁机制,包括内置锁(即 synchronized 关键字)、显式锁(…...
提升阅读体验,Balabolka让文字跃然“声”上
作为一个专业的语音合成工具,Balabolka为用户提供了全方位的文本朗读解决方案。这款软件不仅可以将各类文本实时转换为清晰的语音输出,还能将转换后的音频内容导出为多种主流格式。它强大的兼容性使其能够处理各类电子书和文档格式,让用户可以…...
【汇编语言】call 和 ret 指令(三) —— 深度解析汇编语言中的批量数据传递与寄存器冲突
文章目录 前言1. 批量数据的传递1.1 存在的问题1.2 如何解决这个问题1.3 示例演示1.3.1 问题说明1.3.2 程序实现 2. 寄存器冲突问题的引入2.1 问题引入2.2 分析与解决问题2.2.1 字符串定义方式2.2.2 分析子程序功能2.2.3 得到子程序代码 2.3 子程序的应用2.3.1 示例12.3.2 示例…...
嵌入式C编程:宏定义与typedef的深入对比与应用
目录 一、宏定义(Macro Definition) 1.1. 特点与应用 1.1.1 定义常量 1.1.2 定义函数式宏 1.1.3 条件编译 1.2. 作用范围和生命周期方面 1.3. 应用注意事项 二、typedef 2.1. 特点与应用 2.1.1 简化类型声明 2.1.2 提高代码可读性 2.1.3 实现…...
算法复杂度
目录: 算法的效率时间复杂度 1.算法的效率 1.1旋转数组习题分析 如何衡量一个算法的好坏呢? 案例:旋转数组(189. 轮转数组 - 力扣(LeetCode)) 思路:循环k次将所有元素向后移动一…...
时序约束进阶六:Set_Clock_Groups详解
目录 一、前言 二、时钟间关系 2.1 时钟关系分类 2.2 时钟关系查看 三、set_clock_groups设置 3.1 使用格式 3.2 优先级 3.3 约束设置示例 3.4 约束效果查看 四、Exclusive差异说明 4.1 Asynchronous 4.2 Logically_exclusive与Physically_exclusive 4.3 logical…...
《运放秘籍》第二部:仪表放大器专项知识点总结
一、差分放大器与仪表放大器的讨论 1.1. 仪放的前世今生——差分放大器原理? 1.2. 差分放大的原理 1.3. 差分放大器检测电流 1.4. 差分放大器端一:输入阻抗 1.5. 差分放大器端二:共模抑制比 1.6. 为什么关注输入阻抗?共模抑…...
JavaSE——异常
一、异常的概念 在Java中,将程序执行中发生的不正常行为称为"异常",开发过程中的语法错误和逻辑错误不是异常。 主要分为以下两大类: Error(错误):Java虚拟机无法解决的严重问题,是严重错误,程序…...
HormonyOS: 图形变换之Rotate
官网地址:rotate 1. 概述 rotate是鸿蒙系统为组件提供的旋转属性,通过rotate属性,可实现组件的旋转效果 2. rotate属性 2.1. 语法参数 rotate(value: RotateOptions) 参数: 参数名 类型 必填 说明 value RotateOptions…...
【Solidity】入门指南:智能合约开发基础
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 Solidity入门指南:智能合约开发基础引言1. 开发环境搭建1.1 Remix I…...
HTMLHTML5革命:构建现代网页的终极指南 - 3. 开发工具选择
HTML&HTML5革命:构建现代网页的终极指南 3. 开发工具选择 大家好,我是莫离老师。 前两节课我们学习了 HTML 的基础概念和 HTML5 的主要特性,为接下来的实际开发奠定了理论基础。 今天,我们将讨论开发工具的选择问题。 选择合…...
智能设备安全隐患:五项关键解决措施
目前,我们的智能设备越来越多,而背后的物联网(IoT)安全像一面隐形的盾牌,默默地守护着我们周围那些复杂连网的设备。 为了让大家更加明白这些安全协议和操作是如何高效运作的,我们有必要深入探讨物联网安全…...
Android NDK开发 JNI 基础
在android 系统开发中 ndk开发是很重要的内容。ndk开发中 jni 是基础。 目录 一.什么是JNI 二. 如何使用JNI 1.Java 代码如何调用 c/c 代码 2. c/c如何调用 java 函数 一.什么是JNI JNI——Java Native Interface,它是Java平台的一个特…...
嵌入式linux之文件系统管理
嵌入式Linux文件系统的管理涉及多个方面,包括文件系统的创建、配置、维护以及优化。以下是一些关键点和实践技巧: 文件系统的创建与配置 选择合适的文件系统:根据应用需求(如读写频率、存储介质类型等)选择最合适的文…...
Y20030029 微信+SPRINGBOOT+MYSQL+LW+传统文化展示小程序的设计与实现 源代码 配置 文档
传统文化展示小程序 1.项目描述2. 课题开发的背景与意义3.项目功能4.界面展示5.源码获取 1.项目描述 基于微信小程序的传统文化展示小程序是一个集合了多种传统文化元素与现代化技术的创新平台。它充分利用了微信小程序的便捷性和普及性,为广大用户提供了一个深入了…...
【LC】3232. 判断是否可以赢得数字游戏
题目描述: 给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中,Alice 可以从 nums 中选择所有个位数 或 所有两位数,剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和,则 Alice 获胜。如果…...
【人工智能基础03】机器学习(练习题)
文章目录 课本习题监督学习的例子过拟合和欠拟合常见损失函数,判断一个损失函数的好坏无监督分类:kmeans无监督分类,Kmeans 三分类问题变换距离函数选择不同的起始点 重点回顾1. 监督学习、半监督学习和无监督学习的定义2. 判断学习场景3. 监…...
C/C++每日一练:合并K个有序链表
本篇博客将探讨如何 “合并K个有序链表” 这一经典问题。本文将从题目要求、解题思路、过程解析和相关知识点逐步展开,同时提供详细注释的代码示例。 链表(Linked List) 链表是一种线性数据结构,由一系列节点(Node&…...
jmeter基础07_组件的层级
课程大纲 1. 优先级/执行顺序(一般情况) 同级组件:按组件先后顺序执行。如:同一层的线程组、同一层的http请求。 上下级组件:先执行外层(上级),再执行内层(下级ÿ…...
【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像
【QNX+Android虚拟化方案】125 - 如何创建android-spare镜像 1. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法一2. Android侧创建 (ext4 / sparse) test_img.img 镜像 方法二3. qnx 侧 分区透传Android 配置3.1 配置分区透传3.2 Android 侧分区 rename3.3 创建挂载目…...
大R玩家流失预测在休闲社交游戏中的应用
摘要 预测玩家何时会离开游戏为延长玩家生命周期和增加收入贡献创造了独特的机会。玩家可以被激励留下来,战略性地与公司组合中的其他游戏交叉链接,或者作为最后的手段,通过游戏内广告传递给其他公司。本文重点预测休闲社交游戏中高价值玩家…...
使用Postman搞定各种接口token实战
现在许多项目都使用jwt来实现用户登录和数据权限,校验过用户的用户名和密码后,会向用户响应一段经过加密的token,在这段token中可能储存了数据权限等,在后期的访问中,需要携带这段token,后台解析这段token才…...
【C++】printf 函数详解与格式化输出控制
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯printf 基础用法1.1 printf 的常见占位符1.2 占位符与参数的对应关系1.3 换行控制示例: 💯格式化输出控制2.1 输出宽度控制2.1.1 指定最小宽度 2.2 …...
在21世纪的我用C语言探寻世界本质——字符函数和字符串函数(1)
人无完人,持之以恒,方能见真我!!! 共同进步!! 文章目录 一、字符分类函数二、字符转换函数三、strlen的使用和模拟实现四、strcpy的使用和模拟实现五、strcat的使用和模拟实现六、strcmp的使用和…...
【专题】存储器管理
1. 存储器的层次结构 在计算机执行时,几乎每一条指令都涉及对存储器的访问,因此要求对存储器的访问速度能跟得上处理机的运行速度。 存储器的速度必须非常快,能与处理机的速度相匹配,否则会明显地影响到处理机的运行。 此外还要求…...
python股票数据分析(Pandas)练习
需求: 使用pandas读取一个CSV文件,文件内容包括股票名称、价格和交易量。完成以下任务: 找出价格最高的股票; 计算总交易量; 绘制价格折线图。 代码实现: import pandas as pd import matplotlib.pyplot …...
Hadoop生态圈框架部署(八)- Hadoop高可用(HA)集群部署
文章目录 前言一、部署规划二、Hadoop HA集群部署(手动部署)1. 下载hadoop2. 上传安装包2. 解压hadoop安装包3. 配置hadoop配置文件3.1 虚拟机hadoop1修改hadoop配置文件3.1.1 修改 hadoop-env.sh 配置文件3.3.2 修改 core-site.xml 配置文件3.3.3 修改 …...
抗干扰设计的检查细则
抗干扰设计是确保电子系统或设备在复杂电磁环境中稳定运行的重要环节,涉及多个方面的设计和实施。以下是对抗干扰设计的检查细则的详细归纳: 一、电源线与地线设计 电源线设计:选择合适的电源,尽量加宽电源线,保证电源…...
[Redis#12] 常用类型接口学习 | string | list
目录 0.准备 1.string get | set set_with_timeout_test.cpp set_nx_xx_test.cpp mset_test.cpp mget_test.cpp getrange_setrange_test.cpp incr_decr_test.cpp 2.list lpush_lrange_test.cpp rpush_test.cpp lpop_rpop_test.cpp blpop_test.cpp llen_test.cpp…...
React的ts文件中通过createElement拼接一段内容出来
比如接口返回一个值 const values [23.00, 40.00/kg];想做到如下效果, 如果单纯的用render渲染会很简单, 但是在ts文件中处理,所以采用了createElement拼接 代码如下: format: (values: string[]) > {if (!values || !val…...
【Git系列】Git 提交历史分析:深入理解`git log`命令
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
深度学习笔记——生成对抗网络GAN
本文详细介绍早期生成式AI的代表性模型:生成对抗网络GAN。 文章目录 一、基本结构生成器判别器 二、损失函数判别器生成器交替优化目标函数 三、GAN 的训练过程训练流程概述训练流程步骤1. 初始化参数和超参数2. 定义损失函数3. 训练过程的迭代判别器训练步骤生成器…...
《地球科学与环境学报》
《地球科学与环境学报》报道范围涵盖基础地质、矿产地质、水资源与环境、工程地质、地球物理、地球信息科学等领域,刊载国内外未公开发表的有创新性或意义重大的研究论文和综述文章。 来稿必须包括以下项目:题名(尽可能不要超过20字&…...
k8s 1.28 聚合层部署信息记录
–requestheader-client-ca-file –requestheader-allowed-namesfront-proxy-client –requestheader-extra-headers-prefixX-Remote-Extra- –requestheader-group-headersX-Remote-Group –requestheader-username-headersX-Remote-User –proxy-client-cert-file –proxy-cl…...