Kubernetes(K8s)_15_调度原理

文章目录

  • Pod调度
    • 实现原理
      • 调度队列
        • 优先队列
        • 底层数据
      • 调度缓存
      • 调度框架

Pod调度

Pod调度: 通过污点、容忍度和亲和性影响Pod的调度

  1. 调度器实现, 其基于配置器构造(其配置来源于配置API)
  2. 调度过程中任何插件返回拒绝, 都会导致Pod可能再次返回调度队列

如: Pod调度简略流程

调度简略流程


调度执行流程:

  1. 通过SharedIndedInformer过滤未调度的Pod放入调度队列
  2. 通过SharedIndexInformer过滤已调度的Pod更新调度缓存
  3. 从调度队列中取出个Pod,通过其SchedulerName执行特定调度框架
  4. 调度框架触发调度算法利用调度缓存为Pod选择最优的Node进行异步绑定

实现原理

调度器(Scheduler): Pod调度决策

  1. 调度过程的数据依赖于瞬间的缓存
  2. Pod调度完成后需等待调度插件的批准才可执行绑定
  3. 基于模块: 调度队列调度缓存调度框架调度算法

以下源码分析均都基于v1.28.1版本的Kubernetes源码

// https://github1s.com/kubernetes/kubernetes/blob/HEAD/pkg/scheduler/scheduler.go#64// Scheduler 监视未调度的Pod并尝试找到适合的Node, 并将绑定信息写回到API Server
type Scheduler struct {// Cache 调度缓存, 缓存所有的Node状态// 每次调度前都需更新快照, 以便调度算法使用Cache internalcache.Cache// Extenders 调度插件Extenders []framework.Extender// NextPod 获取下个要调度的Pod, 没有则阻塞goroutine// 不能直接从调度队列中获取调度的Pod, 其不能日志记录调度PodNextPod func() (*framework.QueuedPodInfo, error)// FailureHandler 调度时的回调错误函数FailureHandler FailureHandlerFn// SchedulePod 调度算法给出Pod可调度的NodeSchedulePod func(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod) (ScheduleResult, error)// StopEverything 关闭Scheduler的信号StopEverything <-chan struct{}// SchedulingQueue 缓存等待调度的PodSchedulingQueue internalqueue.SchedulingQueue// Profiles 调度框架的配置(Profile和Frameword属于1:1)Profiles profile.Mapclient                   clientset.InterfacenodeInfoSnapshot         *internalcache.SnapshotpercentageOfNodesToScore int32nextStartNodeIndex       intlogger                   klog.LoggerregisteredHandlers       []cache.ResourceEventHandlerRegistration
}// New 调度器构造函数
func New(ctx context.Context,client clientset.Interface,informerFactory informers.SharedInformerFactory,dynInformerFactory dynamicinformer.DynamicSharedInformerFactory,recorderFactory profile.RecorderFactory,opts ...Option) (*Scheduler, error) {// Kubernetes内部记录器, 并获取终止信号logger := klog.FromContext(ctx)stopEverything := ctx.Done()// 在默认的schedulerOptions基础上应用所有的optsoptions := defaultSchedulerOptionsfor _, opt := range opts {opt(&options)}// 是否应用默认调度框架配置if options.applyDefaultProfile {var versionedCfg configv1.KubeSchedulerConfigurationscheme.Scheme.Default(&versionedCfg)cfg := schedulerapi.KubeSchedulerConfiguration{}if err := scheme.Scheme.Convert(&versionedCfg, &cfg, nil); err != nil {return nil, err}options.profiles = cfg.Profiles}// 创建InTree插件Factory注册表, 并与OutTree插件Factory注册表合并以形成插件Factory注册表// 数据类型为(插件Factory就是插件的构造函数): map[插件名称]插件Factoryregistry := frameworkplugins.NewInTreeRegistry()if err := registry.Merge(options.frameworkOutOfTreeRegistry); err != nil {return nil, err}// 注册调度器的度量标准metrics.Register()// 调度器的扩展程序extenders, err := buildExtenders(logger, options.extenders, options.profiles)if err != nil {return nil, fmt.Errorf("couldn't build extenders: %w", err)}// 获取Pod和Node数据// 以便做成快照数据, 提供调度依据podLister := informerFactory.Core().V1().Pods().Lister()nodeLister := informerFactory.Core().V1().Nodes().Lister()// 初始化快照数据和度量指标记录器(异步)snapshot := internalcache.NewEmptySnapshot()metricsRecorder := metrics.NewMetricsAsyncRecorder(1000, time.Second, stopEverything)// 初始化调度器的配置文件profiles, err := profile.NewMap(ctx, options.profiles, registry, recorderFactory,frameworkruntime.WithComponentConfigVersion(options.componentConfigVersion),frameworkruntime.WithClientSet(client),frameworkruntime.WithKubeConfig(options.kubeConfig),frameworkruntime.WithInformerFactory(informerFactory),frameworkruntime.WithSnapshotSharedLister(snapshot),frameworkruntime.WithCaptureProfile(frameworkruntime.CaptureProfile(options.frameworkCapturer)),frameworkruntime.WithParallelism(int(options.parallelism)),frameworkruntime.WithExtenders(extenders),frameworkruntime.WithMetricsRecorder(metricsRecorder),)if err != nil {return nil, fmt.Errorf("initializing profiles: %v", err)}if len(profiles) == 0 {return nil, errors.New("at least one profile is required")}// 配置中添加PreEnqueue和Queueing Hint// PreEnqueue用于在Pod加入调度队列的前置操作// Queueing Hint过滤事件, 防止调度Pod时的无用重试 preEnqueuePluginMap := make(map[string][]framework.PreEnqueuePlugin)queueingHintsPerProfile := make(internalqueue.QueueingHintMapPerProfile)for profileName, profile := range profiles {preEnqueuePluginMap[profileName] = profile.PreEnqueuePlugins()queueingHintsPerProfile[profileName] = buildQueueingHintMap(profile.EnqueueExtensions())}// 创建调度队列podQueue := internalqueue.NewSchedulingQueue(profiles[options.profiles[0].SchedulerName].QueueSortFunc(),informerFactory,internalqueue.WithPodInitialBackoffDuration(time.Duration(options.podInitialBackoffSeconds)*time.Second),internalqueue.WithPodMaxBackoffDuration(time.Duration(options.podMaxBackoffSeconds)*time.Second),internalqueue.WithPodLister(podLister),internalqueue.WithPodMaxInUnschedulablePodsDuration(options.podMaxInUnschedulablePodsDuration),internalqueue.WithPreEnqueuePluginMap(preEnqueuePluginMap),internalqueue.WithQueueingHintMapPerProfile(queueingHintsPerProfile),internalqueue.WithPluginMetricsSamplePercent(pluginMetricsSamplePercent),internalqueue.WithMetricsRecorder(*metricsRecorder),)// 假定调度指向该调度器的调度队列for _, fwk := range profiles {fwk.SetPodNominator(podQueue)}// 调度缓存// durationToExpireAssumedPod 代表绑定的TTL// 若该时间内未完成绑定, 则从调度缓存中移除该假定调度PodschedulerCache := internalcache.New(ctx, durationToExpireAssumedPod)// 调度器的Debuggerdebugger := cachedebugger.New(nodeLister, podLister, schedulerCache, podQueue)debugger.ListenForSignal(ctx)// 创建调度器, 并从调度队列中弹出个Pod开始调度// 并指定调度器默认的调度流程和调度失败的回调函数sched := &Scheduler{Cache:                    schedulerCache,client:                   client,nodeInfoSnapshot:         snapshot,percentageOfNodesToScore: options.percentageOfNodesToScore,Extenders:                extenders,StopEverything:           stopEverything,SchedulingQueue:          podQueue,Profiles:                 profiles,logger:                   logger,}sched.NextPod = podQueue.Popsched.applyDefaultHandlers()// 注册事件处理函数// 新建Pod先放入调度队列, 绑定成功后由该函数更新调度缓存以确认// 本质: 通过SharedIndexInformer监控Pod和NService等调度依赖的资源, 并根据事件执行对应操作if err = addAllEventHandlers(sched, informerFactory, dynInformerFactory, unionedGVKs(queueingHintsPerProfile)); err != nil {return nil, fmt.Errorf("adding event handlers: %w", err)}return sched, nil
}

调度器执行流程如下(主要通过scheduleOne()方法实现):

  1. 调度器从调度队列中获取个Pod
    • 先通过NextPod()方法从调度队列中获取Pod(可记录日志)
    • 调度器会循环从调度队列中获取Pod, 没有待调度的Pod就直接返回
  2. 对获取的Pod做调度前的预处理
    • 获取Pod指定的调度框架(spec.SchedulerName)
    • 配置Pod调度的环境(计时、CycleStateschedulingCycleCtx等)
  3. 判断是否忽略Pod的调度
    • Pod已被删除, 则直接忽略
    • Pod被更新, 但已调度/假定调度(根据Pod的更新决定是否重新调度)
  4. 通过Score匹配最优Node
    • Score会基于多种因素计算出最适合Pod的Node
    • 若没有Node能满足Pod的资源需求, 则Pod通过PostFilter进行抢占式调度
    • 若Pod是抢占式调度的, 则Pod当前依然是不可调度的(需等待被抢占的Pod优雅退出)
  5. 记录所有调度失败的原因(FailureHandler())
    • 记录导致Pod调度失败的事件(kubectl describe pod命令时的信息)
    • SharedIndexInformer缓存中获取Pod最新状态, 决定是否将调度失败的Pod再次放回调度队列
  6. 假定调度Pod(调度器无需等待可立刻调度下个Pod)
    • 调度缓存中更新Pod已绑定匹配的Node
    • 若TTL内未绑定成功, 则判定假定调度失败并从调度缓存中删除绑定
  7. 为Pod预留全局资源
    • 若预留资源失败, 则删除已预留的资源和调度缓存中假定调度信息并记录失败信息
  8. 判定Pod是否可进入绑定周期
    • 需等待所有插件批准才可执行绑定
    • 若未批准会执行: 删除预留资源、删除假定调度Pod、记录失败信息
  9. Pod绑定Node, 异步执行
    • 绑定预处理(按顺序执行调度框架的各个插件)
    • 执行绑定, 向API Server写入信息(先ExtenderBind, 因部分资源只有前者可管理)
    • 若绑定成功, 则通知调度缓存并记录绑定成功事件(绑定失败也会记录事件)
    • 若绑定失败会执行: 删除预留资源、删除假定调度Pod、记录失败信息

如: 调度整体流程

调度整体流程


调度队列

调度队列(SchedulingQueue): Pod调度过程中的Pod获取顺序

  1. 调度队列具有幂等性(每次操作前均判断是否已存在)
  2. 调度队列的实现是个优先队列(由传入的函数决定其优先级)

优先队列

优先队列(PriorityQueue): 基于map以优先级方式实现调度队列

  1. 优先队列由三个子队列构成: 就绪队列不可调度队列退避队列

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/queue/scheduling_queue.go#L150
// 实现SchedulingQueue接口: https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/queue/scheduling_queue.go#L90// PriorityQueue 优先级方式实现的调度队列
// 
// activeQ(就绪队列): 存储等待被调度的Pod(从该队列中Pop出的Pod), 默认存储新添加的Pod
// backoffQ(退避队列): 存储等待特定时间后可调度的Pod(再次放入activeQ), 等待时间根据尝试次数进行指数级增长(默认上限10s)
// unschedulablePods(不可调度队列): 存储由各种原因导致无法调度的Pod, 经过特定周期后会再次加入activeQ(默认60s)
type PriorityQueue struct {*nominatorstop  chan struct{}clock clock.Clock// podInitialBackoffDuration Pod的初始退避时间, 默认1s// Pod后续每次调度失败, 该时间就以二次方增加podInitialBackoffDuration time.Duration// podMaxBackoffDuration Pod的最大退避时间, 默认10spodMaxBackoffDuration time.Duration// podMaxInUnschedulablePodsDuration Pod可处于unschedulablePods的最大时间podMaxInUnschedulablePodsDuration time.Durationcond sync.Cond// inFlightPods 返回所有当前正在处理的PodinFlightPods map[types.UID]inFlightPod// receivedEvents 返回调度队列收到的所有事件receivedEvents *list.List// activeQ 存储待调度的Pod// 头部Pod是具有最高优先级的Pod(最先调度)activeQ *heap.Heap// podBackoffQ 按照退避时间到期排序// 完成退避的Pod将在调度器查看activeQ之前从其中弹出podBackoffQ *heap.Heap// unschedulablePods 返回已尝试并确定无法调度的PodunschedulablePods *UnschedulablePods// schedulingCycle 返回调度周期schedulingCycle int64// moveRequestCycle 缓存移动请求时的调度周期// 当接受到移动请求并正在调度不可调度Pod时, 则将其放回activeQmoveRequestCycle int64// preEnqueuePluginMap PreEnqueue插件的配置(K为配置文件名)preEnqueuePluginMap map[string][]framework.PreEnqueuePlugin// queueingHintMap Queueing Hint插件的配置(K为配置文件名)queueingHintMap QueueingHintMapPerProfile// closed 队列是否关闭closed boolnsLister                     listersv1.NamespaceListermetricsRecorder              metrics.MetricAsyncRecorderpluginMetricsSamplePercent   intisSchedulingQueueHintEnabled bool
}// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/queue/scheduling_queue.go#L1261// UnschedulablePods 不可调度Pod的队列, 对Map的再次封装
type UnschedulablePods struct {// podInfoMap 存储Pod的map, K为Pod的名称podInfoMap map[string]*framework.QueuedPodInfo// keyFunc 获取对象K的函数keyFunc func(*v1.Pod) string// unschedulableRecorder 监控数据unschedulableRecorder, gatedRecorder metrics.MetricRecorder
}

如: 优先队列的流程

优先队列的流程


底层数据

底层数据: 封装用于调度队列存储对象的底层数据结构

  1. Heap: 对map的再次封装, 具有slice的顺序性和map的高效检索能力
  2. QueuedPodInfo: 对Pod的再次封装, 具有调度队列存储相关的信息

// https://github1s.com/kubernetes/kubernetes/blob/HEAD/pkg/scheduler/framework/types.go#167// QueuedPodInfo 在Pod基础上封装关于调度队列的信息
type QueuedPodInfo struct {*PodInfo// Timestamp Pod添加到调度队列的时间// Pod可能会频繁从取出再放入, 该时间便于处理PodTimestamp time.Time// Attempts Pod重试调度的次数Attempts int// InitialAttemptTimestamp Pod首次添加到调度队列的时间// 初始化后不再更新, 用于计算调度完成所需时间InitialAttemptTimestamp *time.Time// UnschedulablePlugins Pod调度周期中导致失败的插件名称// 仅对PreFilter, Filter, Reserve, Permit(WaitOnPermit)插件有效UnschedulablePlugins sets.Set[string]// Gated 是否由 PreEnqueuePlugin 调度Gated bool
}

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/heap/heap.go#L127// Heap 实现堆数据结构的生产者/消费者队列, 可用于优先级队列类似的数据结构
type Heap struct {// data 存储数据对象data *data// metricRecorder 监控数据metricRecorder metrics.MetricRecorder
}// data 实现标准库的 Heap 接口
type data struct {// items 通过map管理所有对象items map[string]*heapItem// queue 通过slice管理所有对象的K(namespace + pod name)queue []string// keyFunc 获取对象K的函数// 用于操作queue, 应保证该函数的确定性keyFunc KeyFunc// lessFunc 比较两个对象的函数(用于排序)lessFunc lessFunc
}

调度缓存

调度缓存(SchedulerCache): 获取Etcd中Pod和Node的绑定等调度相关所需的信息

  1. Node信息中已包含所有运行在该Node上的Pod信息
  2. 调度缓存会维护段时间已删除的Node, 直到Node没有Pod
  3. 调度缓存中的Node有虚实之分, 虚Node实现Node增加/删除时的正常调度(nodeTree仅存储实Node)

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/cache/cache.go#L57
// 实现Cache接口: https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/cache/interface.go#L60// cacheImpl 实现调度缓存接口
type cacheImpl struct {// top 调度缓存的停止Chanstop <-chan struct{}// ttl 假定调度绑定的超时时间, 默认30sttl time.Duration// period 定期清除假定调度绑定超时的Pod, 默认60speriod time.Duration// mu 读写锁保证并发安全mu sync.RWMutex// assumedPods 假定调度Pod集合assumedPods sets.Set[string]// podStates 所有Pod信息podStates map[string]*podState// nodes 所有Node信息nodes map[string]*nodeInfoListItem// headNode Node双向链表中首个Node// 基于特定规则排序, 链表的排序效率高于sliceheadNode *nodeInfoListItem// nodeTree 节点按照zone组成成的树状数据结构nodeTree *nodeTree// imagesStates 镜像状态imageStates map[string]*imageState
}

快照(Snapshot): 调度缓存某瞬间下的副本

  1. 作用:通过增量更新和只读, 避免频繁获取和读写锁损失性能
  2. 调度器在执行每个调度周期前, 都会获取个快照作为调度的数据依据
  3. 每次调度都会根据调度缓存更新快照中的Node信息以保证状态一致(仅更新部分信息)

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/internal/cache/snapshot.go#L29// Snapshot 缓存 NodeInfo 和 NodeTree 快照
type Snapshot struct {// nodeInfoMap Node信息(map[namespace + name]NodeInfo)nodeInfoMap map[string]*framework.NodeInfo// nodeInfoList 按照NodeTree排序的Node全集列表(不包含已删除的Node)nodeInfoList []*framework.NodeInfo// havePodsWithAffinityNodeInfoList 处理具有亲和性的PodhavePodsWithAffinityNodeInfoList []*framework.NodeInfo// havePodsWithRequiredAntiAffinityNodeInfoList 处理具有反亲和性的PodhavePodsWithRequiredAntiAffinityNodeInfoList []*framework.NodeInfo// usedPVCSet 调度Pod使用的PVCusedPVCSet sets.Set[string]// generation Node的配置纪元// 所有NodeInfo.Generation中的最大值(其均源于全局Generation变量)generation int64
}

假定调度Pod(Assume): 调度结果写入Etcd

  1. 异步绑定假定结果, 调度器继续调度其他Pod以保证性能
  2. 假定调度绑定时会预先占用资源防止再次分配, 但真正绑定失败会释放占用资源
  3. 假定调度Pod具有绑定限定时间, 超时未真正绑定会释放占用资源和清除假定调度Pod
  4. 当真正绑定时会删除假定调度Pod, 并对假定调度Pod占用资源进行转移

如: 调度缓存流程

调度缓存流程


调度框架

调度框架: Kubernetes调度器的插件架构(调度插件的集合)

  1. 扩展点: 调度插件注册后执行位置(提供信息或调度决策)
  2. Pod的调度流程分为两个周期: 调度周期(串行)绑定周期(并行)
  3. 句柄(Handler): 为插件提供服务(提供额外功能, 协助插件完成功能)
    • 配置后的调度框架就是个调度器, 配置后的调度插件就是个调度算法

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/framework/runtime/framework.go#L49
// 实现Framework接口: https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/framework/interface.go#L512// frameworkImpl
type frameworkImpl struct {// registry 调度插件注册表, 通过其创建配置的插件registry Registry// snapshotSharedLister 基于快照的ListersnapshotSharedLister framework.SharedLister// waitingPods 存储等待批准的PodwaitingPods *waitingPodsMap// scorePluginWeight 插件的权重映射(K为插件名称)scorePluginWeight map[string]int// 所有扩展点的插件, 用于实现Framework接口的各个方法// 每个扩展点都会遍历执行插件, 且均在构造函数中通过SchedulingProfile生成preEnqueuePlugins    []framework.PreEnqueuePluginenqueueExtensions    []framework.EnqueueExtensionsqueueSortPlugins     []framework.QueueSortPluginpreFilterPlugins     []framework.PreFilterPluginfilterPlugins        []framework.FilterPluginpostFilterPlugins    []framework.PostFilterPluginpreScorePlugins      []framework.PreScorePluginscorePlugins         []framework.ScorePluginreservePlugins       []framework.ReservePluginpreBindPlugins       []framework.PreBindPluginbindPlugins          []framework.BindPluginpostBindPlugins      []framework.PostBindPluginpermitPlugins        []framework.PermitPluginclientSet       clientset.InterfacekubeConfig      *restclient.ConfigeventRecorder   events.EventRecorderinformerFactory informers.SharedInformerFactorylogger          klog.LoggermetricsRecorder          *metrics.MetricAsyncRecorderprofileName              stringpercentageOfNodesToScore *int32extenders []framework.Extenderframework.PodNominatorparallelizer parallelize.Parallelizer
}

如: 调度周期和绑定周期执行流程(调度上下文)

调度上下文

  1. Kubernetes集群中可存在多个调度框架
  2. 扩展点是插件的设计接口, 调度需12个插件
  3. 带有Pre前缀的插件都是提供信息的, 其他均是做决策的
  4. 调度框架就是个调度器, 配置好的调度插件就是调度算法

调度插件: 影响Pod调度的各组件

  1. 调度插件分为多种, 而每个调度插件可有多种实现
  2. 调度插件都虚静态编译到注册中, 且通过唯一性的名称区分
  3. 插件均是无状态的(插件存储状态需依赖外部实现), 且插件间通信依赖于CycleState
  4. 每种插件类型可实现多种类型的插件接口(该插件可在插件框架中的多个扩展位置作用)

// https://github1s.com/kubernetes/kubernetes/blob/release-1.28/pkg/scheduler/framework/cycle_state.go#L48// CycleState 基于共享变量实现插件之间数据传输
// 仅作为单词调度周期中, 各个插件之间通信(调度上下文)
// 
// 未提供任何数据保护, 对所有插件都认为是可信的
type CycleState struct {// storage 存储数据storage sync.Map// recordPluginMetrics 是否监控recordPluginMetrics bool// SkipFilterPlugins 将在Filter扩展点忽略的插件SkipFilterPlugins sets.Set[string]// SkipScorePlugins 将在Score扩展点忽略的插件SkipScorePlugins sets.Set[string]
}

调度框架中各调度插件的说明:

插件名称说明
Sort排序等待调度的Pod
(默认按照优先级)
PreFilter处理Pod相关信息为过滤Node做准备
(过滤前的处理)
Filter过滤无法运行该Pod的Node
(对多节点并发应用多个Filter插件)
PostFilter抢占调度
(仅在Filter过滤不出Node时执行)
PreScore处理Pod相关信息为Node评分做准备
(主要处理亲和性、拓扑分步和容忍度)
Score对所有过滤的Node评分并排序
(首个Node则为Pod的最优选择)
NormalizeScore修改已排序的Node评分
(提高Node评分的扩展性)
Reserve维护全局调度状态
(防止下次调度与本次绑定完成前发生竞争)
Premit标注Pod状态以防止或延迟Pod绑定
(Pod状态可为: 批准、等待、延迟)
Prebind处理Pod绑定需完成的操作
(常用于完成PV和PVC)
BindPod与Node绑定
(仅作用单个Bind插件)
PostBind清理绑定期间使用的资源
(没有默认实现, 用于自定义扩展)
  1. Pre前缀的插件是预处理并提供信息, 同时避免部分真正重量操作重复执行

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

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

相关文章

moduo之tcp客户端TcpClient

结构 #mermaid-svg-muvN6eOMXA4rCyXP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-muvN6eOMXA4rCyXP .error-icon{fill:#552222;}#mermaid-svg-muvN6eOMXA4rCyXP .error-text{fill:#552222;stroke:#552222;}#merm…

中国科技术语杂志中国科技术语杂志社中国科技术语编辑部2025年第3期目录

理论研究 认知术语学与社会认知术语学比较研究 吴小芳; 3-11 大语言模型背景下的术语翻译研究&#xff1a;现状、问题与展望 朱玉彬;王梓; 12-20 航空事件谣言叙事中的术语初探 刘成盼;刘东亮; 21-28 定名研讨 浅谈训诂、训诂学和训诂学术语 林童; 29-35 …

自然语言处理NLP期末复习

目录 第一章1. NLP的基本过程包括哪些-自然语言处理面临的困难是什么2. 自然语言处理算法定义&#xff0c;过程和应用3. 结合自己的研究-描述研究中涉及的自然语言处理模型或算法&#xff0c;模型或算法原理&#xff0c;具体的处理过程4. 自然语言处理的的两大核心任务是5. 程序…

单片机 - STM32F103“复用功能重映射”完整解析:从JTAG释放到TIM重映射实战详解

本文将详细讲解 STM32F103 系列中常见的“复用功能重映射”&#xff08;Remap&#xff09;机制&#xff0c;包括 JTAG 占用、引脚默认功能与复用功能的关系&#xff0c;以及如何通过寄存器或标准库代码实现重映射。以 TIM3 在 PB4/PB5 上输出 PWM 为例&#xff0c;进行实战讲解…

【C语言】知识总结·内存函数

目录 前言&#xff1a; 一、内存复制函数 1. memcpy - 内存块复制 2. memmove - 内存块移动 二、内存设置函数 1. memset - 内存块填充 三、内存比较函数 1. memcmp 2.memchr 三内存分配函数 1 .malloc 2.free 总结&#xff1a; 注意事项&#xff1a; 前言&…

python+uniapp基于微信小程序面向品牌会员的在线商城系统

文章目录 具体实现截图本项目支持的技术路线源码获取详细视频演示&#xff1a;文章底部获取博主联系方式&#xff01;&#xff01;&#xff01;&#xff01;本系统开发思路进度安排及各阶段主要任务java类核心代码部分展示主要参考文献&#xff1a;源码获取/详细视频演示 ##项目…

小鱼fish系统 sudo apt update报错(密钥失效)

在使用小鱼fish提供的系统镜像文件&#xff0c;sudo apt update系统更新时遇到了以下报错&#xff0c;即ROS 2 仓库的 GPG 密钥已过期&#xff0c;以及 Docker 仓库使用了过时的密钥存储方式 fishrosfishros-linux:~$ sudo apt update 获取:1 http://mirrors.tuna.tsinghua.ed…

深度优先搜索 (DFS) 详解

1. 什么是深度优先搜索&#xff1f; 深度优先搜索&#xff08;Depth-First Search, DFS&#xff09;是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都已被探寻过&#xff0c;搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进…

文心4.5开源大模型的使用和部署

前言 就在今天&#xff0c;文心4.5模型开源了&#xff0c;不是一个&#xff0c;而是整个系列模型正式开源。很突然&#xff0c;我都震惊了。文心4.5系列开源模型共10款&#xff0c;涵盖了激活参数规模分别为47B 和3B 的混合专家&#xff08;MoE&#xff09;模型&#xff08;最…

HarmonyOs开发之——TypeScript介绍、入门,及 TypeScript、JavaScript、ArkTs的具体区别解读。

HarmonyOs开发之——TypeScript介绍、入门&#xff0c;及 TypeScript、JavaScript、ArkTs的具体区别解读。 一、 开发语言介绍&#xff1a; TypeScript是JavaScript的超集&#xff0c;ArkTS则是TypeScript的超集。ArkTs是 HarmonyOs的主力开发语言&#xff0c;它在TypeScript…

《JMS事务性会话彻底解析:消息监听中的 commit、rollback 和幂等设计》

大家好&#xff0c;我是G探险者&#xff01; &#x1f4cc; 场景引入 在实际项目中&#xff0c;我们常常面临以下挑战&#xff1a; 监听 MQ 消息失败了&#xff0c;希望自动重试&#xff1f;消费 MQ 消息后&#xff0c;要写数据库&#xff0c;但中间报错了&#xff1f;消息处…

vue3 el-table 列增加 自定义排序逻辑

在 Vue 3 中使用 Element Plus 的 <el-table> 组件时&#xff0c;如果你想增加自定义排序逻辑&#xff0c;可以通过以下几个步骤实现&#xff1a; 1. 使用 default-sort 属性 首先&#xff0c;你可以在 <el-table> 组件上使用 default-sort 属性来指定默认的排序…

ISP Pipeline(7): Gamma Correction 伽马校正

AI_Plays/ISP/Fast_ISP_Progress.ipynb at main ameengee/AI_Plays GitHub Gamma Correction&#xff08;伽马校正&#xff09;是图像处理中的一个重要步骤&#xff0c;目的是调整图像的亮度&#xff0c;使其更符合人眼的感知或显示设备的特性。 为什么需要 Gamma Correcti…

AI提取伴奏,实现卡拉OK效果 —— 「suno api/luno api/kuka api」

导读 喜欢唱歌&#xff0c;却总苦于找不到纯净的伴奏&#xff1f;或者你想把喜欢的歌曲翻唱一遍&#xff0c;却被人声干扰搞得头大&#xff1f;现在&#xff0c;AI技术已经悄悄解决了这个问题。借助AI智能工具&#xff0c;你可以轻松提取任何一首歌的伴奏&#xff0c;享受宛如…

pip介绍

pip是什么&#xff1f; pip&#xff08;Pip Installs Packages&#xff09;是Python的官方管理工具&#xff0c;用于安装、升级、卸载和管理Python第三方库及其依赖关系。它是Python生态系统的核心组件&#xff0c;通过连接PyPI&#xff08;Python Package Index&#xff09;这…

机器学习20-线性网络思考

机器学习20-线性网络思考 针对线性网络的基础问题&#xff0c;使用基础示例进行解释 1-核心知识点 1-线性模型家族的线性回归和逻辑回归分别是什么&#xff0c;线性模型家族还有没有其他的模型 线性模型家族是一系列基于线性假设的统计模型&#xff0c;它们假设因变量和自变量…

【科研绘图系列】R语言绘制世界地图分布(world map)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理准备画图画图总结系统信息介绍 本教程旨在通过R语言及其相关地理空间分析包,展示如何对环境数据进行空间聚类分析,并将结果可视化。教程从读…

Armbian 25.5.1 Noble Gnome 开启远程桌面功能

sudo apt install gnome-remote-desktop ----长话短说 故障表现 Ubuntu 25版本点击远程桌面功能没有任何反应, WIN_20250630_00_53_24_Pro 最后 armbian 官方社区充满了傲慢,一言不合就关闭话题,问题都没有解决就给我关闭了 最后检索到英文网站,说到了这么一句话,检查远程桌…

嵌入式 Linux 入门:从裸机到系统级开发的第一步

随着嵌入式系统应用的不断深入&#xff0c;很多 MCU 项目开发者会在某个阶段遇到瓶颈&#xff1a;系统越来越复杂、任务越来越多、通信越来越频繁、性能要求越来越高。 这时候&#xff0c;从 MCU / RTOS 过渡到 嵌入式 Linux 开发 就成为一次技术升级的关键转折点。 本文将带…

详解 Blazor 组件传值

父子组件传值 在 Blazor 中&#xff0c;组件之间的通信可以通过 [Parameter] 参数和 EventCallback<T> 事件回调实现。下面分别给出 父组件传递值给子组件 和 子组件传递值给父组件 的简单示例。 1.1 父组件传递值给子组件 步骤&#xff1a; 在子组件中定义 public 属…