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

React16源码: React中的schedule调度整体流程

schedule调度的整体流程

  • React Fiber Scheduler 是 react16 最核心的一部分,这块在 react-reconciler 这个包中
  • 这个包的核心是 fiber reconciler,也即是 fiber 结构
  • fiber 的结构帮助我们把react整个树的应用,更新的流程,能够拆成每一个 fiber 对象为单元的一个更新的流程
  • 这种单元的形式把更新拆分出来之后,给每个不同的任务提供一个优先级,以及我们在更新的过程当中,可以中断
  • 因为我们记录更新到了哪一个单元,中断了之后,可以过一会儿再回过头来,继续从这个单元开始,继续之前没有做完的更新
    • 在 react 16之前 setState 产生的更新,必须从头到尾更新完成,然后再执行之后的代码
    • 如果我们的整个应用树,它的节点非常多,整个更新会导致它占用的js的运行时间会非常的多
    • 让页面的其他的一些操作进入一个停滞的状态
    • 比如说,动画的刷新或者是我们在 input 里面输入内容的时候,可能产生卡顿的感觉
  • 所以,react 16之后,它的整体的更新流程是完全不一样的
    • 因为加入了中断,挂起,这样的功能,导致它的整个更新流程的调度变得非常的复杂
    • 整个源码体系,它每一个细节,每一个变量的具体作用,都是值得琢磨的
    • 理解它出于什么目的这么去设计,这时候才能深入整个react的更新体系中,这样才能慢慢理解

全局变量一览

  • 调度过程中的全局变量,基本上都在 react-reconciler/src/ReactFiberScheduler.js 这个js里面
    • https://github.com/facebook/react/blob/v16.6.3/packages/react-reconciler/src/ReactFiberScheduler.js
  • 这个js的代码是非常多的,它总共有两千五百行代码,而且注释不算多
  • 在这个文件里面,会存在着非常多的公共变量,就是说我们定义在这个文件的顶层的变量名
  • 就是说我们定义在这个文件顶层作用域上面的很多的变量,在很多方法里面,它们是被共享的
  • 这些公共变量对于去理解整个 schedule,它是非常重要的,因为它在很多方法里面都会有调用
    • 它什么时候调用,什么时候被修改成什么值,用来记录什么内容
    • 对于这些公共变量的理解,一方面来说比较的困难
    • 另外一方面来说,它非常的重要
    • 如果不能理解这些公共变量的作用,会导致看源码的时候,看到一些地方会变得毫无头绪

几个重点需要关注的变量

// Used to ensure computeUniqueAsyncExpiration is monotonically decreasing.
let lastUniqueAsyncExpiration: number = Sync - 1;let isWorking: boolean = false;// The next work in progress fiber that we're currently working on.
let nextUnitOfWork: Fiber | null = null;
let nextRoot: FiberRoot | null = null;
// The time at which we're currently rendering work.
let nextRenderExpirationTime: ExpirationTime = NoWork;
let nextLatestAbsoluteTimeoutMs: number = -1;
let nextRenderDidError: boolean = false;// The next fiber with an effect that we're currently committing.
let nextEffect: Fiber | null = null;let isCommitting: boolean = false;
let rootWithPendingPassiveEffects: FiberRoot | null = null;
let passiveEffectCallbackHandle: * = null;
let passiveEffectCallback: * = null;let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;// Used for performance tracking.
let interruptedBy: Fiber | null = null;let stashedWorkInProgressProperties;
let replayUnitOfWork;
let mayReplayFailedUnitOfWork;
let isReplayingFailedUnitOfWork;
let originalReplayError;
let rethrowOriginalError;
  • isWorking

    • commitRoot和renderRoot开始都会设置为true,然后在他们各自阶段结束的时候都重置为false
    • 用来标志是否当前有更新正在进行,不区分阶段
  • isCommitting

    • commitRoot开头设置为true,结束之后设置为false
    • 用来标志是否处于commit阶段
  • nextUnitOfWork

    • 用于记录render阶段Fiber树遍历过程中下一个需要执行的节点。
    • 在resetStack中分别被重置
    • 它只会指向workInProgress
  • nextRoot & nextRenderExpirationTime

    • 用于记录下一个将要渲染的root节点和下一个要渲染的任务的
  • nextEffect

    • 用于commit阶段记录firstEffect -> lastEffect链遍历过程中的每一个Fiber

下面是其他的一些全局变量

// Linked-list of roots
let firstScheduledRoot: FiberRoot | null = null;
let lastScheduledRoot: FiberRoot | null = null;let callbackExpirationTime: ExpirationTime = NoWork;
let callbackID: *;
let isRendering: boolean = false;
let nextFlushedRoot: FiberRoot | null = null;
let nextFlushedExpirationTime: ExpirationTime = NoWork;
let lowestPriorityPendingInteractiveExpirationTime: ExpirationTime = NoWork;
let hasUnhandledError: boolean = false;
let unhandledError: mixed | null = null;let isBatchingUpdates: boolean = false;
let isUnbatchingUpdates: boolean = false;let completedBatches: Array<Batch> | null = null;let originalStartTimeMs: number = now();
let currentRendererTime: ExpirationTime = msToExpirationTime(originalStartTimeMs,
);
let currentSchedulerTime: ExpirationTime = currentRendererTime;// Use these to prevent an infinite loop of nested updates
const NESTED_UPDATE_LIMIT = 50;
let nestedUpdateCount: number = 0;
let lastCommittedRootDuringThisBatch: FiberRoot | null = null;
  • firstScheduledRoot & lastScheduledRoot

    • 用于存放有任务的所有root的单链表结构
    • 在findHighestPriorityRoot用来检索优先级最高的root
    • 在addRootToSchedule中会修改
  • callbackExpirationTime & callbackID

    • 记录请求ReactScheduler的时候用的过期时间,如果在一次调度期间有新的调度请求进来了
    • 而且优先级更高,那么需要取消上一次请求,如果更低则无需再次请求调度。
    • callbackID是ReactScheduler返回的用于取消调度的 ID
  • isRendering

    • performWorkOnRoot开始设置为true,结束的时候设置为false
    • 表示进入渲染阶段,这是包含render和commit阶段的
  • nextFlushedRoot & nextFlushedExpirationTime

    • 用来标志下一个需要渲染的root和对应的expirtaionTime
  • deadline & deadlineDidExpire

    • deadline是ReactScheduler中返回的时间片调度信息对象
    • 用于记录是否时间片调度是否过期,在shouldYield根据deadline是否过期来设置
  • isBatchingUpdates & isUnbatchingUpdates & isBatchingInteractiveUpdates

    • batchedUpdates、unBatchedUpdates,deferredUpdates、interactiveUpdates等这些方法用来存储更新产生的上下文的变量
  • originalStartTimeMs

    • 固定值,js 加载完一开始计算的时间戳
  • currentRendererTime & currentSchedulerTime

    • 计算从页面加载到现在为止的毫秒数,后者会在isRendering === true的时候
    • 用作固定值返回,不然每次requestCurrentTime都会重新计算新的时间。
  • 以上,每一个全局变量给它拿出来,单独解释它是在什么地方被用到

  • 以及它是用来记录哪些东西,是在什么情况下,才会发挥了哪些作用

调度流程


1 )第一阶段

  • 在调用 ReactDOM.render, setState, forceUpdate,都会产生一个update
  • 产生update之后,进入 scheduleWork 进行调度
    • scheduleWork 第一步操作是 addRootToScheduler
    • 在一个rect应用当中,它不仅仅可能只存在一个 root 节点
    • 因为我们通过 ReactDOM.render 调用的时候,就会创建一个 root 节点
    • 如果调用多次 ReactDOM.render,就可以创建多个 root 节点
    • 这个时候, 整个应用中就会存在着多个react的节点
    • 在这些节点,可以单独在内部进行 setState,进行调度
    • 它们都会有独立的 updateQueen,有独立的一个 fiber tree 来进行应用的更新
    • 一个应用当中可能会存在多个root, 所以这个时候就要去维护一下
    • 因为,在同一时间可能有多个root会有更新存在, 所以有这么一个地方去维护它
    • 这就是 addRootToScheduler 的一个作用
  • addRootToScheduler 加入之后, 要先判断一下是否正在 render 阶段 或者 前后的root不同
    • 如果是,则调用 requestWork,就要开始进行工作了,如果不是,我们就要 return
    • 因为之前的任务可能正在做,或者处于目前这个阶段,不需要主动的再去调用一个 requestWork 来更新了
  • 关于 requestWork 它里面做了什么?
    • 它判断 expirationTime,它是否是 Sync
    • 计算 expirationTime 调用的是 computeExpirationForFiber
    • 这时候会根据 fiber 是否有 ConcurrentMode 的特性来计算 Sync 的 expirationTime 或者是异步的 expirationTime
    • 这个时候它最终会导致整体的一个更新模式的不同
    • 因为如果是 Sync 的模式代表着我们这个更新要立马进行执行,要立马更新到最终的 dom tree 上面
    • 所以我们调用的是 performSyncWork
    • 而如果它是一个 Async 模式的,那么说明它的优先级不是特别高,那么他会进入一个调度的流程,因为它可以不立即更新
    • 它本身的期望是在 expirationTime 结束之前,能够被更新完成就可以了, 所以它的优先级非常低,会进入到一整个调度的流程,即 scheduleCallbackWithExpirationTime

2 )下一阶段

  • 整个调度的流程 react 给它单独区分了一个包 packages/scheduler
    • 用蓝色的框给它圈起来,叫做 async schedule work
  • 这一部分就涉及到整个异步的调度的过程
    • 它利用的是浏览器当中一个较新的API叫做 requestIdleCallback, 能够让浏览器优先进行他自己的任务
    • 比如说更新动画,在每一帧有多余的时间的时候,它调用react给他设置了一个callback
    • 然后就可以去执行react一个更新,然后react会自己去记一个时
    • 在这个时间内,我可以执行我自己的工作
    • 如果这个时间内我的工作没有执行完,我要把javascript的运行的主动权交还给浏览器
    • 让浏览器去执行它新的一些动画的更新之类的,来让浏览器保证高优先级的任务能够被立即执行
    • 所以,这就是这个蓝色这一片区域的一个作用
  • 在这里面调用的一个方法叫做 scheduleDeferredCallback, 然后会有一个 callbackList
  • 因为可能多次调用这个方法去把 callback 设置进去
  • 然后在这里面,我们虽然想要使用 requestIdleCallback 这个API
  • 但是, 大部分浏览器还不支持, 浏览器的兼容性也不是特别好
  • 所以在react里面,它实现了自己的一个模拟 requestIdleCallback 的一个方式
    • 它通过 requestAnimationFramejs 的任务队列的原理来进行了一个模拟
  • 在调用 requestIdleCallback 之后,说明浏览器有空了,可以去执行react的更新了
    • 这就是我们加入到这里面的异步的更新任务,它的优先级比较低,浏览器有空的时候,再来执行
    • 因为 react 的任务它是有一个 expirationTime 的
    • 所以它这里要判断一下我的任务有没有超时
    • 如果已经超时了,要把所有加入callbackList队列的超时任务都执行掉
    • 因为任务已经超时了,所以必须要立刻完成
    • 执行到第一个非超时的任务之后,若还有时间,可以继续执行
    • 如果没有时间了,要把主动权交还给浏览器,让浏览器来做其他一些任务
  • 最终要执行这个任务,执行的是什么?
    • 调用一个 performAsyncWork 这个方法
    • 它会执行react的schedule里面的回调函数
    • 在调用这个方法的时候,schedule 会传给这个方法一个叫做deadline的一个对象,这个对象是用来判断。
    • 在进入 performAsyncWork 的时候,就进入到react的一个更新流程
    • react的更新流程中,它去遍历整一棵树,会遍历每棵树的每个单元,然后对它进行一个更新的操作
    • 每个单元更新完了之后,回过头来通过这个deadline对象判断一下,现在是否还有 js 运行的一个时间片
    • 因为调度器每一次调用 performAsyncWork 的任务,它是有一个时间限制的
    • 比如说默认的情况下是22毫秒,在这个时间片内你可以去执行的操作
    • 这就是这个 deadline 对象它的一个作用
  • 最终调用 performWork 这个方法
  • performWork 它调用的是没有deadline的
  • performAsyncWork 它调用的是有deadline的
  • 最终在 if deadline 这里汇集在一起
  • 根据是否有 deadline 进入下个阶段的循环

3 )第三个阶段

  • 根据是否有 deadline 进入循环
  • 这个循环是什么呢?
    • 这个循环就是要遍历整棵树每一个 fiber 节点进行的更新操作
  • 对于同步任务,它会遍历完整棵树,然后把整个应用更新就完了
    • 因为它是同步的,跟以前的react用法是一样的
  • 对于异步的来讲,如果符合条件
    • 进入 performWorkOnRoot, 它做的其实是一个更新的过程
    • 然后 findHighestPriorityRoot 找到一个最高优先级的节点之后
    • 对这个节点进行一个更新 recomputeCurrentRendererTime
    • 对于有 deadline 的情况,调用 performWorkOnRoot 进行更新任务之后
    • renderRoot 里面,它还会有一个循环去判断 deadline
    • 最终要等这个 performWorkOnRoot 返回之后,才会继续下面的操作
    • 对于有 deadline 的情况,会重新请求一个时间,然后去判断一下deadline是否已经过期
    • 如果已经过期的话,会回过头来到红色区域再进行一个判断
    • 如果发现 deadline 已经过期的话,又会去继续调用这个 scheduleCallbackWithExpirationTime
    • 再次进行异步的回调, 它这是一个递归的过程
    • 因为之前第一阶段加入了一个 addRootToScheduler
    • 它就有一个队列,在维护着所有的更新的情况
    • 对于每一次更新,只能更新一个优先级的任务,以及一个root上的任务
    • 上述红色这块区域,它就是一个循环的条件判断
    • 它每次更新一个节点上的一个优先级任务
    • 具体的操作在 performWorkOnRoot 里面
    • 更新完之后, 它会去调用相对应的方法
    • 在这个root上对应的优先级任务更新完之后
    • 它要找到下一个root上面的对应优先级的任务,然后再次进入这个循环
    • 所以这个就是deadline它的一个用处,它帮助我们去判断是否应该跳出循环了
    • 如果我们一直处于这个循环,要把所有任务都更新完,那么可能占用的js运行时间会非常的长
    • 导致可能的动画停滞或用户输入卡顿。
    • 在这个 deadline 超过了之后,这个循环直接跳出
    • 然后再继续跳回到这个 scheduleCallbackWithExpirationTime
    • 再次进入一个调度,然后把js的执行权交给浏览器,让它先执行动画或者用户输入的响应
    • 等有空了,再回过头来再去执行这个任务,然后又回到 红色区域判断这里
    • 之前没完成的任务,再继续这么一个循环
    • 最终达到的目的是要把 root 里面的所有的节点上面的所有更新都执行完为止
    • 这就是整的一个循环的一个过程

整体流程图

总结

  • 通过 ReactDOM.render, setState, forceUpdate 这几个方法产生了更新
  • 产生了更新之后,维护一个队列去保存这些更新以及对应的root节点
  • 然后,根据它任务的优先级来进行判断,判断是同步的更新还是异步的更新
    • 对于异步的更新,如果有多个任务,它会一直处于先执行浏览器优先级最高的更新
    • 有空的时候回过头来更新 react 树
    • 如果 root 上对应的某一个优先级的任务更新完了
    • 那么先输出到dom上,然后执行下一个更新
    • 在这个循环的过程当中,根据这个调度器传入的 deadline 对象
    • 判断是否有超时,如果超时,再回过头去进行一个调度
    • 先把执行权给浏览器,让它保证动画的流畅运行
    • 等它有空,再回过头来继续执行的任务
  • 这就是整个调度的核心原理
  • 目的是
    • 保证我们低优先级的react更新,不会阻止浏览器的一些高要求的动画更新
    • 能够保证浏览器的一些动画能够达到30帧以上这么一个情况
  • 以上就是react整个的调度过程

相关文章:

React16源码: React中的schedule调度整体流程

schedule调度的整体流程 React Fiber Scheduler 是 react16 最核心的一部分&#xff0c;这块在 react-reconciler 这个包中这个包的核心是 fiber reconciler&#xff0c;也即是 fiber 结构fiber 的结构帮助我们把react整个树的应用&#xff0c;更新的流程&#xff0c;能够拆成…...

springboot mybatis-plus swing实现报警监听

通过声音控制报警器&#xff0c;实现声光报警&#xff0c;使用beautyeye_lnf.jar美化界面如下 EnableTransactionManagement(proxyTargetClass true) SpringBootApplication EnableScheduling public class AlarmWarnApplication {public static void main(String[] args) …...

【计算机网络】网络层——详解IP协议

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】 本专栏旨在分享学习计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 &#x1f431;一、I…...

【Java数据结构】03-二叉树,树和森林

4 二叉树、树和森林 重点章节&#xff0c;在选择&#xff0c;填空&#xff0c;综合中都有考察到。 4.1 掌握二叉树、树和森林的定义以及它们之间的异同点 1. 二叉树&#xff08;Binary Tree&#xff09; 定义&#xff1a; 二叉树是一种特殊的树结构&#xff0c;其中每个节点…...

Element UI Input组件内容格式化:换行时行首添加圆点

<el-input v-model"input"placeholder"请输入"type"textarea":rows"8"focus"handleFocus"input.native"handleInput" /> 解释一下&#xff1a; Element UI对 input 事件做了一层包装&#xff0c;无法返回…...

十、Qt 操作PDF文件

《一、QT的前世今生》 《二、QT下载、安装及问题解决(windows系统)》《三、Qt Creator使用》 ​​​ 《四、Qt 的第一个demo-CSDN博客》 《五、带登录窗体的demo》 《六、新建窗体时&#xff0c;几种窗体的区别》 《七、Qt 信号和槽》 《八、Qt C 毕业设计》 《九、Qt …...

开源软件合规风险与开源协议的法律效力

更多内容&#xff1a;​​​​​​OWASP TOP 10 之敏感数据泄露 OWASP TOP 10 之失效的访问控制 ​​​​​​OWASP TOP 10 之失效的身份认证 一、开源软件主要合规风险 1、版权侵权风险 没有履行开源许可证规定的协议导致的版权侵权&#xff0c;例如没有按照许可要求的保留…...

2024全新开发API接口调用管理系统网站源码 附教程

2024全新开发API接口调用管理系统网站源码 附教程 用layui框架写的 个人感觉很简洁 方便使用和二次开发...

[Linux 进程(四)] 再谈环境变量,程序地址空间初识

文章目录 1、前言2、环境变量2.1 main函数第三个参数 -- 环境参数表2.2 本地环境变量和env中的环境变量2.3 配置文件与环境变量的全局性2.4 内建命令与常规命令2.5 环境变量相关的命令 3、程序地址空间 1、前言 上一篇我们讲了环境变量&#xff0c;如果有不明白的先读一下上一…...

【C++】STL(标准模板库)

文章目录 1. 基本概念2. 容器2.1. 容器的分类2.2. vector2.2.1. 构造vector对象2.2.2. vector的赋值 1. 基本概念 STL&#xff08;Standard Template Library&#xff0c;标准模板库)是惠普实验室开发的一系列软件的统称&#xff0c;现在已经成为C标准库的重要组成部分。STL的…...

【已解决】fatal: Authentication failed for ‘https://github.com/.../‘

文章目录 异常原因解决方法 异常原因 在 Linux 服务器上使用git push命令&#xff0c;输入用户名和密码之后&#xff0c;总会显示一个报错&#xff1a; fatal: Authentication failed for https://github.com/TianJiaQi-Code/Linux.git/ # 致命&#xff1a;无法通过验证访问起…...

SqlAlchemy使用教程(二) 入门示例及编程步骤

SqlAlchemy使用教程(一) 原理与环境搭建SqlAlchemy使用教程(三) CoreAPI访问与操作数据库详解 二、入门示例与基本编程步骤 在第一章中提到&#xff0c;Sqlalchemy提供了两套方法来访问数据库&#xff0c;由于Sqlalchemy 官方文档结构有些乱&#xff0c;对于ORM的使用步骤的描…...

HTML+JS+CSS移动端购物车选购界面

代码打包资源下载&#xff1a;【免费】HTMLJSCSS移动端购物车选购界面资源-CSDN文库 关键部分说明&#xff1a; UIGoods 类&#xff1a; 构造函数&#xff1a; 创建 UIGoods 实例时&#xff0c;传入商品数据 g&#xff0c;初始化商品的数据和选择数量。getTotalPrice() 方法…...

微服务治理:为什么要分析微服务的依赖关系?

在微服务架构中&#xff0c;单个服务相互协作以交付功能。这些协作会在服务之间形成依赖关系&#xff0c;其中一个服务依靠另一个服务来完成自己的任务。虽然依赖关系使功能得以实现&#xff0c;但不受控制的依赖关系可能会导致一系列挑战&#xff1a; 复杂性: 错综复杂的依赖…...

【程序员的自我修养—系统调用与API】

系统调用 背景&#xff1a; 为了避免有限的系统资源被多个不同的应用程序同时访问&#xff0c;需要加以保护&#xff0c;避免冲突&#xff1b;提供一套统一的接口&#xff0c;是应用程序能做一些由操作系统支持的行为&#xff1b;接口通过中断的方式实现&#xff0c;Linux使用…...

使用宝塔面板部署后端项目到服务器

文章目录 前言第一步&#xff1a;安装数据库第二步&#xff1a;打包后端项目第三步&#xff1a;配置数据库第四步&#xff1a;部署后端项目第五步&#xff1a;前后端联调测试总结 前言 在之前我已经写了一篇如何去部署前端项目&#xff0c;虽然能访问网站&#xff0c;但是没有…...

走迷宫(c语言)

前言&#xff1a; 制作一个迷宫游戏是一个有趣的编程挑战。首先&#xff0c;我们需要设计一个二维数组来表示迷宫的布局&#xff0c;其中每个元素代表迷宫中的一个格子。我们可以使用不同的值来表示空格、墙壁和起点/终点。接下来&#xff0c;我们需生成迷宫。在生成迷宫的过程…...

两周掌握Vue3(五):自定义指令、路由、ajax

文章目录 一、自定义指令1.创建和使用自定义指令2.钩子函数3.使用参数 二、路由1.创建一个router实例2.在components目录中创建组件3.将路由实例挂载到应用4.使用路由 三、Ajax 代码仓库&#xff1a;跳转 当前分支&#xff1a;05 一、自定义指令 自定义指令是Vue.js框架提供的…...

redis之单线程和多线程

目录 1、redis的发展史 2、redis为什么选择单线程&#xff1f; 3、主线程和Io线程是怎么协作完成请求处理的&#xff1f; 4、IO多路复用 5、开启redis多线程 1、redis的发展史 Redis4.0之前是用的单线程&#xff0c;4.0以后逐渐支持多线程 Redis4.0之前一直采用单线程的主…...

12AOP面向切面编程/GoF之代理模式

先看一个例子&#xff1a; 声明一个接口&#xff1a; // - * / 运算的标准接口! public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j); }实现该接口&#xff1a; package com.sunsplanter.prox…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...