executor行为相关Spark sql参数源码分析

news2024/11/28 21:57:25

0、前言

参数名和默认值
spark.default.parallelism=Default number of partitions in RDDs
spark.executor.cores=1 in YARN mode 一般默认值
spark.files.maxPartitionBytes=134217728(128M)
spark.files.openCostInBytes=4194304 (4 MiB)
spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version=1 不同版本算法task提交数据

【重点】在spark sql中有对应参数为:

spark.sql.files.maxPartitionBytes=134217728(128M)  本次重点源码分析
spark.sql.files.openCostInBytes=4194304  (4 MiB) 本次重点源码分析
spark.default.parallelism = math.max(totalCoreCount.get(), 2)

对应源码位置如下:

org.apache.spark.scheduler.cluster.CoarseGrainedSchedulerBackend#defaultParallelism

org.apache.spark.sql.internal.SQLConf#FILES_MAX_PARTITION_BYTES

org.apache.spark.sql.internal.SQLConf#FILES_OPEN_COST_IN_BYTES

1、 环境准备

create database bicoredata;

CREATE TABLE bicoredata.dwd_start_log_dm(
`device_id` string,
`area` string,
`uid` string,
`app_v` string,
`event_type` string,
`os_type` string,
`channel` string,
`language` string,
`brand` string,
`entry` string,
`action` string,
`error_code` string
)
comment 'dwd用户启动日志信息'
partitioned by (`dt` string)
stored as orc
tblproperties("orc.compress"="ZLIB")
location '/bicoredata/dwd_start_log_dm';


-- 解析ods日志到dwd表

insert overwrite table bicoredata.dwd_start_log_dm
partition(dt='20220721')
select get_json_object(line, '$.attr.device_id'),
get_json_object(line, '$.attr.area'),
get_json_object(line, '$.attr.uid'),
get_json_object(line, '$.attr.app_v'),
get_json_object(line, '$.attr.event_type'),
get_json_object(line, '$.attr.os_type'),
get_json_object(line, '$.attr.channel'),
get_json_object(line, '$.attr.language'),
get_json_object(line, '$.attr.brand'),
get_json_object(line, '$.app_active.json.entry'),
get_json_object(line, '$.app_active.json.action'),
get_json_object(line, '$.app_active.json.error_code')
from 
(
select split(str, ' ')[7] as  line
from biods.ods_start_log
where dt='20220721'
)t

2、 代码准备

package org.example.sparksql

import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession

object SparkSqlHive {
  def main(args: Array[String]): Unit = {
    System.setProperty("HADOOP_USER_NAME", "root")
    // 动态分配参数必须 在 yarn环境下才能生效,client/cluster
    val ss = SparkSession.builder().master("yarn").appName("the test of SparkSession")
      .config("spark.deploy.mode","cluster")
      .config("yarn.resourcemanager.hostname", "hadoop2")
      // 注意只有设置为true,才是文件读取算子,否则是表读取算子。
     .config("spark.sql.hive.convertMetastoreOrc", "true")
      .config("spark.sql.files.maxPartitionBytes","34008864")  //注意不是spark.files.maxPartitionBytes
      .config("spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version","2")
      .config("spark.dynamicAllocation.enabled","true")
      .config("spark.shuffle.service.enabled","true")
      .config("spark.driver.host","192.168.150.1")
      .enableHiveSupport().getOrCreate()

    ss.sql("DROP TABLE IF EXISTS temp.temp_ods_start_log");
    val df = ss.sql("insert overwrite table bicoredata.dwd_start_log_dm " +
                    "partition(dt='20210721') " +
                    "select get_json_object(line, '$.attr.device_id')," +
                    "get_json_object(line, '$.attr.area')," +
                    "get_json_object(line, '$.attr.uid')," +
                    "get_json_object(line, '$.attr.app_v')," +
                    "get_json_object(line, '$.attr.event_type')," +
                    "get_json_object(line, '$.attr.os_type')," +
                    "get_json_object(line, '$.attr.channel')," +
                    "get_json_object(line, '$.attr.language')," +
                    "get_json_object(line, '$.attr.brand')," +
                    "get_json_object(line, '$.app_active.json.entry')," +
                    "get_json_object(line, '$.app_active.json.action')," +
                    "get_json_object(line, '$.app_active.json.error_code') " +
                    "from " +
                    "(" +
                      "select split(str, ' ')[7] as  line " +
                      "from biods.ods_start_log " +
                      "where dt='20210721'" +
                    ")t")
    Thread.sleep(1000000)
    ss.stop()
  }
}

输入:
hdfs中该日期分区存有2个文件,大小分别为245M和94M
请添加图片描述
输出:
最终结果分区中,有6个文件。
请添加图片描述

可见缩小spark.sql.files.maxPartitionBytes值,增大了读取task数量。

3 、源码分析

3.1 、物理执行计划如下

Execute InsertIntoHadoopFsRelationCommand hdfs://hadoop1:9000/bicoredata/dwd_start_log_dm, Map(dt -> 20210721), false, [dt#55], ORC, Map(orc.compress -> ZLIB, serialization.format -> 1, partitionOverwriteMode -> dynamic), Overwrite, CatalogTable(
Database: bicoredata
Table: dwd_start_log_dm
Owner: root
Created Time: Sun Dec 11 17:47:33 CST 2022
Last Access: UNKNOWN
Created By: Spark 2.2 or prior
Type: MANAGED
Provider: hive
Comment: dwd????????
Table Properties: [orc.compress=ZLIB, transient_lastDdlTime=1670752053]
Location: hdfs://hadoop1:9000/bicoredata/dwd_start_log_dm
Serde Library: org.apache.hadoop.hive.ql.io.orc.OrcSerde
InputFormat: org.apache.hadoop.hive.ql.io.orc.OrcInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat
Storage Properties: [serialization.format=1]
Partition Provider: Catalog
Partition Columns: [`dt`]
Schema: root
 |-- device_id: string (nullable = true)
 |-- area: string (nullable = true)
 |-- uid: string (nullable = true)
 |-- app_v: string (nullable = true)
 |-- event_type: string (nullable = true)
 |-- os_type: string (nullable = true)
 |-- channel: string (nullable = true)
 |-- language: string (nullable = true)
 |-- brand: string (nullable = true)
 |-- entry: string (nullable = true)
 |-- action: string (nullable = true)
 |-- error_code: string (nullable = true)
 |-- dt: string (nullable = true)
), org.apache.spark.sql.execution.datasources.CatalogFileIndex@df5f9368, [device_id, area, uid, app_v, event_type, os_type, channel, language, brand, entry, action, error_code, dt]
+- Project [ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.device_id) as string) AS device_id#43, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.area) as string) AS area#44, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.uid) as string) AS uid#45, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.app_v) as string) AS app_v#46, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.event_type) as string) AS event_type#47, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.os_type) as string) AS os_type#48, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.channel) as string) AS channel#49, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.language) as string) AS language#50, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.attr.brand) as string) AS brand#51, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.app_active.json.entry) as string) AS entry#52, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.app_active.json.action) as string) AS action#53, ansi_cast(get_json_object(split(str#1,  , -1)[7], $.app_active.json.error_code) as string) AS error_code#54, 20210721 AS dt#55]
   +- *(1) ColumnarToRow
      +- FileScan orc biods.ods_start_log[str#1,dt#2] Batched: true, DataFilters: [], Format: ORC, Location: InMemoryFileIndex[hdfs://hadoop1:9000/bi/ods/ods_start_log/dt=20210721], PartitionFilters: [isnotnull(dt#2), (dt#2 = 20210721)], PushedFilters: [], ReadSchema: struct<str:string>

如上所示,本质上分三部分:
(1)读取表
FileScan orc biods.ods_start_log
(2)转换
Project [ansi_cast(get_json_object(split(str#1, , -1)[7]
(3)写入目标表
Execute InsertIntoHadoopFsRelationCommand

3.2 、FileScan和InsertIntoHadoopFsRelationCommand 算子

从InsertIntoHadoopFsRelationCommand 开始源码分析如下:

org.apache.spark.sql.execution.datasources.InsertIntoHadoopFsRelationCommand#run

org.apache.spark.sql.execution.datasources.FileFormatWriter$#write

org.apache.spark.sql.execution.FileSourceScanExec#inputRDD

FileSourceScanExec#createNonBucketedReadRDD

org.apache.spark.sql.execution.FileSourceScanExec#createNonBucketedReadRDD
首次出现3个相关参数

private def createNonBucketedReadRDD(
    readFile: (PartitionedFile) => Iterator[InternalRow],
    selectedPartitions: Array[PartitionDirectory],
    fsRelation: HadoopFsRelation): RDD[InternalRow] = {
    // 对应spark.sql.files.openCostInBytes 参数 
  val openCostInBytes = fsRelation.sparkSession.sessionState.conf.filesOpenCostInBytes
   // 基于3个参数计算出来
  val maxSplitBytes =
    FilePartition.maxSplitBytes(fsRelation.sparkSession, selectedPartitions)
  logInfo(s"Planning scan with bin packing, max size: $maxSplitBytes bytes, " +
    s"open cost is considered as scanning $openCostInBytes bytes.")

    // 逻辑分割orc文件,返回分区的文件对象PartitionedFile
  val splitFiles = selectedPartitions.flatMap { partition =>
    partition.files.flatMap { file =>
      // getPath() is very expensive so we only want to call it once in this block:
      val filePath = file.getPath
       // orc文件是可以分割的,对应org.apache.spark.sql.hive.orc.OrcFileFormat#isSplitable函数,返回true
      val isSplitable = relation.fileFormat.isSplitable(
        relation.sparkSession, relation.options, filePath)
      PartitionedFileUtil.splitFiles(
        sparkSession = relation.sparkSession,
        file = file,
        filePath = filePath,
        isSplitable = isSplitable,
        maxSplitBytes = maxSplitBytes,
        partitionValues = partition.values
      )
    }
  }.sortBy(_.length)(implicitly[Ordering[Long]].reverse)

    // 基于分区文件对象,最大分割尺寸,返回文件分区FilePartition对象(逻辑层面)
  val partitions =
    FilePartition.getFilePartitions(relation.sparkSession, splitFiles, maxSplitBytes)

    // 返回rdd
  new FileScanRDD(fsRelation.sparkSession, readFile, partitions)
}
FilePartition和PartitionedFile区别

(1)FilePartition对象:会被单个任务读取的PartitionedFile集合
对应源码在 org.apache.spark.sql.execution.datasources.FilePartition
--》特点是,一个FilePartition对应1个task

(2)PartitionedFile对象:用于读取的单个文件的部分,包含文件路径,开始偏移量,读取长度偏移量
-->特点是,一个PartitionedFile对应1个文件的部分,有对应的开始偏移量和读取偏移量

FilePartition#maxSplitBytes

org.apache.spark.sql.execution.datasources.FilePartition#maxSplitBytes
综合以上3个关键参数,计算出最大分割大小。

def maxSplitBytes(
    sparkSession: SparkSession,
    selectedPartitions: Seq[PartitionDirectory]): Long = {
    // 对应 spark.sql.files.maxPartitionBytes 参数,默认128M
  val defaultMaxSplitBytes = sparkSession.sessionState.conf.filesMaxPartitionBytes
    // 对应spark.sql.files.openCostInBytes 参数 ,默认4M
  val openCostInBytes = sparkSession.sessionState.conf.filesOpenCostInBytes
    // 对应 spark.default.parallelism参数,默认应该会取到2(yarn cluster集群默认环境下测试结果)
  val defaultParallelism = sparkSession.sparkContext.defaultParallelism
  val totalBytes = selectedPartitions.flatMap(_.files.map(_.getLen + openCostInBytes)).sum
  val bytesPerCore = totalBytes / defaultParallelism

  Math.min(defaultMaxSplitBytes, Math.max(openCostInBytes, bytesPerCore))
}

org.apache.spark.scheduler.cluster.CoarseGrainedSchedulerBackend#defaultParallelism

override def defaultParallelism(): Int = {
  conf.getInt("spark.default.parallelism", math.max(totalCoreCount.get(), 2))
}

PartitionedFileUtil#splitFiles

org.apache.spark.sql.execution.PartitionedFileUtil#splitFiles

def splitFiles(
    sparkSession: SparkSession,
    file: FileStatus,
    filePath: Path,
    isSplitable: Boolean,
    maxSplitBytes: Long,
    partitionValues: InternalRow): Seq[PartitionedFile] = {
  if (isSplitable) {
    (0L until file.getLen by maxSplitBytes).map { offset =>
      val remaining = file.getLen - offset
      val size = if (remaining > maxSplitBytes) maxSplitBytes else remaining
      val hosts = getBlockHosts(getBlockLocations(file), offset, size)
        // 基于偏移量,size构造分区file对象
      PartitionedFile(partitionValues, filePath.toUri.toString, offset, size, hosts)
    }
  } else {
    Seq(getPartitionedFile(file, filePath, partitionValues))
  }
}

逻辑分割结果,11个文件,降序排列:
请添加图片描述

FilePartition#getFilePartitions

org.apache.spark.sql.execution.datasources.FilePartition#getFilePartitions

def getFilePartitions(
    sparkSession: SparkSession,
    partitionedFiles: Seq[PartitionedFile],
    maxSplitBytes: Long): Seq[FilePartition] = {
  val partitions = new ArrayBuffer[FilePartition]
  val currentFiles = new ArrayBuffer[PartitionedFile]
  var currentSize = 0L

  /** Close the current partition and move to the next. */
  def closePartition(): Unit = {
    if (currentFiles.nonEmpty) {
      // 将PartitionedFile文件数组封装成1个FilePartition对象
      val newPartition = FilePartition(partitions.size, currentFiles.toArray)
      partitions += newPartition
    }
    currentFiles.clear()
    currentSize = 0
  }

  val openCostInBytes = sparkSession.sessionState.conf.filesOpenCostInBytes
  // Assign files to partitions using "Next Fit Decreasing"
  partitionedFiles.foreach { file =>
    if (currentSize + file.length > maxSplitBytes) {
      closePartition()
    }
    // Add the given file to the current partition.
    currentSize += file.length + openCostInBytes
    currentFiles += file
  }
    // 处理最后1个分区文件
  closePartition()
  partitions
}

总体调用流程

请添加图片描述
InsertIntoHadoopFsRelationCommand为物理逻辑计划的最后1个算子,其run方法,包含写入数据和更新元数据过程;其中写入数据又包含生成FileScanRDD(11个分区)和提交job过程。

请添加图片描述
stage0的初始rdd,即为FileScanRDD。

由于FileScanRDD包含11个FilePartition,所以 最终生成11个task
请添加图片描述
请添加图片描述

4、疑问

4.1、预期11 个task 大小均匀分布 32M左右,但为什么实际存在一些task空跑,其他task输入大小为62M多?

经了解发现,以hdfs://hadoop1:9000/bi/ods/ods_start_log/dt=20210721/000000_1orc文件为例,其由4个stripe组成,大小刚好为62.5M,62.5M,62.5M,58.6M,且不可分割,这就与task中大小和数量不谋而合。

orc原理参考: https://www.jianshu.com/p/0ba4f5c3f113

查看orc文件的stripe个数等信息

hive --orcfiledump hdfs://hadoop1:9000/bi/ods/ods_start_log/dt=20210721/000001_0 | less

结果如下
请添加图片描述

4.2、测试sql中不涉及join,group by等shuffle操作,为什么会溢出到内存,甚至磁盘?

请添加图片描述

下面是exectuor中,spark task运行的线程dump中,可以发现有堆内存溢出的操作。

猜测:可能有shuffle或者排序,因为如果是纯map task任务,如果excutor内存不足,会直接报oom错误。

请添加图片描述

org.apache.spark.sql.execution.SortExec#doExecute

//task执行过程中,会到这一步。
protected override def doExecute(): RDD[InternalRow] = {
    val peakMemory = longMetric("peakMemory")
    val spillSize = longMetric("spillSize")
    val sortTime = longMetric("sortTime")

    child.execute().mapPartitionsInternal { iter =>
      val sorter = createSorter()

      val metrics = TaskContext.get().taskMetrics()
      // Remember spill data size of this task before execute this operator so that we can
      // figure out how many bytes we spilled for this operator.
      val spillSizeBefore = metrics.memoryBytesSpilled
        // 说明sort过程会 溢出数据到内存
      val sortedIterator = sorter.sort(iter.asInstanceOf[Iterator[UnsafeRow]])
      sortTime += NANOSECONDS.toMillis(sorter.getSortTimeNanos)
      peakMemory += sorter.getPeakMemoryUsage
      spillSize += metrics.memoryBytesSpilled - spillSizeBefore
      metrics.incPeakExecutionMemory(sorter.getPeakMemoryUsage)

      sortedIterator
    }

sortExec工作原理 : https://zhuanlan.zhihu.com/p/582664919
当没有足够的内存来存储指针阵列列表或分配的内存页,或者UnsafeInMemorySorter的行数大于或等于溢出阈值numElementsForSpillThreshold时,内存中的数据将被分割到磁盘。

为什么会有sortExec算子?

在 InsertIntoHadoopFsRelationCommand 命令,提交job之前。

org/apache/spark/sql/execution/datasources/FileFormatWriter.scala:170

// 查看requiredChildOrderings针对排序有特殊需求的添加SortExec节点
val rdd = if (orderingMatched) {
  empty2NullPlan.execute()
} else {
  // SPARK-21165: the `requiredOrdering` is based on the attributes from analyzed plan, and
  // the physical plan may have different attribute ids due to optimizer removing some
  // aliases. Here we bind the expression ahead to avoid potential attribute ids mismatch.
  val orderingExpr = bindReferences(
    requiredOrdering.map(SortOrder(_, Ascending)), outputSpec.outputColumns)
    // 这里绑定上了sortexec 算子,返回的是rdd,并非已经开始计算了
  SortExec(
    orderingExpr,
    global = false,
    child = empty2NullPlan).execute()
}

val rddWithNonEmptyPartitions = if (rdd.partitions.length == 0) {
        sparkSession.sparkContext.parallelize(Array.empty[InternalRow], 1)
      } else {
        rdd
      }

      val jobIdInstant = new Date().getTime
      val ret = new Array[WriteTaskResult](rddWithNonEmptyPartitions.partitions.length)
// 然后这里才提交了job
      sparkSession.sparkContext.runJob(
        rddWithNonEmptyPartitions,
        (taskContext: TaskContext, iter: Iterator[InternalRow]) => {
          executeTask(
            description = description,
            jobIdInstant = jobIdInstant,
            sparkStageId = taskContext.stageId(),
            sparkPartitionId = taskContext.partitionId(),
            sparkAttemptNumber = taskContext.taskAttemptId().toInt & Integer.MAX_VALUE,
            committer,
            iterator = iter)
        },
        rddWithNonEmptyPartitions.partitions.indices,
        (index, res: WriteTaskResult) => {
          committer.onTaskCommit(res.commitMsg)
          ret(index) = res
        })

参考:https://developer.aliyun.com/article/679260

4.3、resulttask

不涉及shuffle的sql 最终生成的只有resultTask, 当然也只有resultstage。

org.apache.spark.rdd.RDDCheckpointData$
请添加图片描述

请添加图片描述

executetask即 传入 rdd上执行的func

org.apache.spark.scheduler.ResultTask#runTask

请添加图片描述

org.apache.spark.sql.execution.datasources.FileFormatWriter#executeTask

里面包含提交task的过程

参考:https://blog.csdn.net/weixin_42588332/article/details/122440644#:~:text=%E5%AF%B9%E4%BA%8E%20Aggregate%20%E6%93%8D%E4%BD%9C%EF%BC%8CSpark%20UI%20%E4%B9%9F%E8%AE%B0%E5%BD%95%E7%9D%80%E7%A3%81%E7%9B%98%E6%BA%A2%E5%87%BA%E4%B8%8E%E5%B3%B0%E5%80%BC%E6%B6%88%E8%80%97%EF%BC%8C%E5%8D%B3%20Spill%20size%20%E5%92%8C,%E7%9A%84%E5%B3%B0%E5%80%BC%E6%B6%88%E8%80%97%EF%BC%8C%E8%AF%81%E6%98%8E%E5%BD%93%E5%89%8D%203GB%20%E7%9A%84%20Executor%20Memory%20%E8%AE%BE%E7%BD%AE%EF%BC%8C%E5%AF%B9%E4%BA%8E%20Aggregate%20%E8%AE%A1%E7%AE%97%E6%9D%A5%E8%AF%B4%E6%98%AF%E7%BB%B0%E7%BB%B0%E6%9C%89%E4%BD%99%E7%9A%84%E3%80%82

https://zhuanlan.zhihu.com/p/431015932

https://blog.csdn.net/chongqueluo2709/article/details/101006130

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

snap使用interface:content的基础例子

snap做包还在学习阶段&#xff0c;官网文档可查看&#xff1a;The content interface | Snapcraft documentation该例子由publiser和consumer两部分组成&#xff0c;一个提供一个只读的数据区&#xff0c;一个来进行读取其中的信息&#xff0c;这样就完成了content的交互。publ…

华为机试题:HJ90 合法IP(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

ICASSP 2023论文模型开源|语音分离Mossformer

人类能在复杂的多人说话环境中轻易地分离干扰声音&#xff0c;选择性聆听感兴趣的主讲人说话。但这对机器却不容易&#xff0c;如何构建一个能够媲美人类听觉系统的自动化系统颇具挑战性。 本文将详细解读ICASSP2023本届会议收录的单通道语音分离模型Mossformer论文&#xff0…

EXCEL职业版本(3)

Excel职业版本&#xff08;3&#xff09; 公式与函数 运算符 算数运算符 关系运算符 地址的引用 相对引用&#xff1a;你变它就变&#xff0c;如影随形 A2&#xff1a;A5 绝对引用&#xff1a;以不变应万变 $A$2 混合引用&#xff1a;识时务者为俊杰&#xff0c;根据时…

tkinter实现悬浮文字

悬浮文字效果如下图&#xff1a;不可点击&#xff0c;不可选中&#xff0c;任务栏不显示图标&#xff0c;文字背景完全透明。 实现方法&#xff1a; root.wm_overrideredirect(True) wm_overrideredirect方法&#xff0c;在Windows平台下&#xff0c;这个函数的作用&#xff…

项目规模估算如何精准 4大注意事项

项目报价&#xff0c;需要首先进行项目规模估算&#xff0c;如何估算更精准&#xff0c;6大注意事项。 1、项目范围规划 在项目估算前&#xff0c;需要对项目范围进行规划&#xff0c;这包括所有活动以及开发可交付产品所需的流程。范围规划是前提&#xff0c;它明确定义了项目…

操作系统内核与安全分析课程笔记【1】链表、汇编与makefile

文章目录链表循环双向链表哈希链表其他链表汇编内联汇编扩展内联汇编makefile链表 链表是linux内核中关键的数据结构。在第二次课中&#xff0c;重点介绍了循环双向链表和哈希链表。这两种链表都在传统的双向链表的基础之上进行了针对效率的优化。(ps&#xff1a;这部分可以通…

smp_init过程解析

当你看到这样的log&#xff0c;会不会很慌张&#xff1f;竟然由CPU没有启动成功&#xff0c;除了什么故障&#xff1f;本文将结合我遇到的一个问题&#xff0c;将启动过程中bringup secondary cpu的过程分析一下。smp_init代码如下&#xff1a;602 void __init smp_init(void) …

合肥工业大学密码学课设-RSA

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;课设-密码学课设-RSA &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#…

牛客刷题第一弹

1.异常处理 都是Throwable的子类&#xff1a; ①.Exception&#xff08;异常&#xff09;:是程序本身可以处理的异常。 ②.Error&#xff08;错误&#xff09;: 是程序无法处理的错误。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时&#xff0c;一般不需…

百丽时尚×优维科技×道客战略启动「云原生一体化项目」

3月7日&#xff0c;由百丽时尚集团&#xff08;以下简称&#xff1a;百丽时尚&#xff09;联合优维科技、道客共同举办的「云原生一体化项目启动会」在深圳百丽国际大厦圆满落幕&#xff0c;项目合作三方齐聚一堂&#xff0c;就云原生一体化建设战略方案达成合作共识&#xff0…

【LeetCode每日一题】——783.二叉搜索树节点最小距离

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【题目注意】九【时间频度】十【代码实现】十一【提交结果】一【题目类别】 深度优先搜索 二【题目难度】 简单 三【题目编号】 783.二叉搜索树节点最小距…

Hands-on C++ Game Animation Programming阅读笔记(九)

Chapter 12: Blending between Animations This fade is usually short—a quarter of a second or less. (动画之间的fade一般很快&#xff0c;0.5s甚至更短) 本章重点&#xff1a; 两个Pose的Blending不同Animations的CrossFading&#xff0c;会有一个cross fade controller…

OpenCV入门(六)快速学会OpenCV5图像处理基础(二)像素处理

OpenCV入门&#xff08;六&#xff09;快速学会OpenCV5图像处理基础&#xff08;二&#xff09; 像素是图像构成的基本单位&#xff0c;像素处理是图像处理的基本操作&#xff0c;可以通过位置索引的形式对图像内的元素进行访问、处理。 1.二值化操作 需要说明的是&#xff…

2023年上半年北京杭州/广州深圳软考中/高级报名入口

软考是全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;项目&#xff0c;是由国家人力资源和社会保障部、工业和信息化部共同组织的国家级考试&#xff0c;既属于国家职业资格考试&#xff0c;又是职称资格考试。 系统集成…

【人脸识别】ssd + opencv Eigenfaces 和 LBPH算法进行人脸监测和识别

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言ssd opencv Eigenfaces 和 LBPH算法进行人脸监测和识别1. ssd 目标监测2.opencv的三种人脸识别方法2.1 Eigenfaces2.2 LBPH前言 ssd opencv Eigenfaces 和 LB…

hadoop的补充配置与常用脚本

目录 历史服务器的配置&#xff1a; 添加配置&#xff1a; 分发集群&#xff1a; 日志聚集功能的配置&#xff1a; 添加配置&#xff1a; 分发配置给集群其他服务器&#xff1a; 集群的启动与停止&#xff1a; 整体启动和停止hdfs&#xff1a; 整体启动/停止YARN 启动…

微服务为什么要用到 API 网关?

本文介绍了 API 网关日志的价值&#xff0c;并以知名网关 Apache APISIX 为例&#xff0c;展示如何集成 API 网关日志。 作者程小兰&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Contributor。 原文链接 什么是微服务 微服务架构&#xff08;通常简称为微服务&a…

Promise.all、Promise.race、Promise.allSettled、Promise.any区别

1.Promise.all Promise.all()方法用于将多个 Promise 实例&#xff0c;包装成一个新的 Promise 实例。 const p Promise.all([p1, p2, p3]); p的状态由p1,p2,p3 决定&#xff0c;分成两种情况。 &#xff08;1&#xff09;只有p1、p2、p3的状态都变成fulfilled&#xff0c…

LeetCode - 42 接雨水

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例1 输入&…