React进阶之React核心源码解析(二)
React核心源码解析
- diff
- 单一节点比较diff
- 多节点比较diff
- 两轮遍历比较
- 第一轮比较
- 第二轮比较
- Update 状态更新
- Concurrent Mode
diff
一共两个阶段
- render:内存中的更新,主要是通过递归的过程,来将react变化的部分,在内存中找到哪些元素是需要发生变化的,针对需要发生变化的内容,会打上标,也就是
Update
,针对这些需要Update的组件,会拿着上一次与当前这一次的节点,通过Fiber
(专门的数据结构存储当前的组件/模块)进行此次与上一次元素更新之间对比。
diff 的过程,其实就是Update Fiber
的过程,diff的结果就是生成一个经过Update更新之后的新的Fiber的节点。 - commit:同步的过程,同步渲染到浏览器端/客户端的过程
- 针对不同类型的元素
从
<div><Component />
</div>
到
<span><Component />
</span>
这是不同类型元素的展示,在Fiber中,定义当前组件类型不一致的时候,是需要将当前树全部销毁重建的
因此,在开发过程中,需要尽可能减少元素的变化。
- 针对相同类型元素
从
<ul className="hello"><li>1</li> <li>2</li>
</ul>
到
<ul className="world"><li>3</li> <li>4</li><li>5</li>
</ul>
就是在render
的阶段中,相同类型的节点进行diff
判断,并不会立马更新。生成mutation
要变化的内容,针对不同diff进行汇总,然后在commit
过程中,对dom的节点直接进行操作。
但是 上述例子中,如果是针对第一个元素<li>之前进行添加的话,会将所有的子列表全部销毁掉,重新创建,
就比如,从
<ul className="hello"><li>1</li> <li>2</li>
</ul>
到
<ul className="world"><li>3</li> <li>1</li><li>2</li>
</ul>
这样的情况
这时候,通过key
的方式去解决,并且尽可能保证每个key是唯一的,不要去使用index作为key来传输
跟一个真实DOM相关联的是:
- current fiber:当前的fiber节点,表达当前DOM的 内存对象
- workInProgress fiber:内存中变化的节点,表达接下来在内存中需要进行操作的对象
- DOM:在commit过程中生成的真实的dom
- JSX:真实代码
通过current fiber
和JSX
比较,更新到workInProgress fiber
,进行current fiber和workInProgress fiber的互换,拿着workInProgress fiber替换生成到真实DOM
。
- 同级元素的比较
- 不同类型元素 销毁当前节点&所有子节点
- key
// 根据newChild类型选择不同diff函数处理
function reconcileChildFibers(returnFiber: Fiber,currentFirstChild: Fiber | null,newChild: any,
): Fiber | null {//这里的newChild是fiber节点,不是dom元素了const isObject = typeof newChild === 'object' && newChild !== null;//如果是对象的话,那么就是单一的节点if (isObject) {// object类型,可能是 REACT_ELEMENT_TYPE 或 REACT_PORTAL_TYPEswitch (newChild.$$typeof) {case REACT_ELEMENT_TYPE:// 调用 reconcileSingleElement 处理// // ...省略其他case}}if (typeof newChild === 'string' || typeof newChild === 'number') {// 调用 reconcileSingleTextNode 处理// ...省略}//如果是数组的话,则是多个节点if (isArray(newChild)) {// 调用 reconcileChildrenArray 处理// ...省略}// 一些其他情况调用处理函数// ...省略// 以上都没有命中,删除节点return deleteRemainingChildren(returnFiber, currentFirstChild);
}
单一节点比较diff
function reconcileSingleElement(returnFiber: Fiber,currentFirstChild: Fiber | null,element: ReactElement
): Fiber {const key = element.key;let child = currentFirstChild;// 首先判断是否存在对应DOM节点while (child !== null) {// 上一次更新存在DOM节点,接下来判断是否可复用// 首先比较key是否相同if (child.key === key) {// key相同,接下来比较type是否相同switch (child.tag) {// ...省略casedefault: {if (child.elementType === element.type) {// type相同则表示可以复用// 返回复用的fiberreturn existing;}// type不同则跳出switchbreak;}}// 代码执行到这里代表:key相同但是type不同// 将该fiber及其兄弟fiber标记为删除deleteRemainingChildren(returnFiber, child);break;} else {// key不同,将该fiber标记为删除deleteChild(returnFiber, child);}child = child.sibling;}// 创建新Fiber,并返回 ...省略
}
针对单一的节点:
- key是否一样
- 一样
- type 一样:同一个DOM
- type不一样:当前节点和所有的兄弟节点sibling全都删除
- 不一样
- 直接删除
- 一样
举例:
全部删除:
// 更新前
<div>a</div>
// 更新后
<p>a</p>// 更新前
<div key="xxx">a</div>
// 更新后
<div key="ooo">a</div>
只更新内容:
// 更新前
<div key="xxx">a</div>
// 更新后
<div key="xxx">b</div>
多节点比较diff
isArray方法比较
- 节点更新
// 更新前
<ul><li key="0" className="before">0<li><li key="1">1<li>
</ul>// 更新后 情况1 —— 节点属性变化
<ul><li key="0" className="after">0<li><li key="1">1<li>
</ul>// 更新后 情况2 —— 节点类型更新
<ul><div key="0">0</div><li key="1">1<li>
</ul>
节点属性变化,只需要更新即可
节点类型变化,则当前<li>和兄弟节点全部推倒重建
- 节点新增和删除
// 更新前
<ul><li key="0">0<li><li key="1">1<li>
</ul>// 更新后 情况1 —— 新增节点
<ul><li key="0">0<li><li key="1">1<li><li key="2">2<li>
</ul>// 更新后 情况2 —— 删除节点
<ul><li key="1">1<li>
</ul>
- 节点位置变化,顺序调整
// 更新前
<ul><li key="0">0<li><li key="1">1<li>
</ul>// 更新后
<ul><li key="1">1<li><li key="0">0<li>
</ul>
这里key不一样,全部删除重建
两轮遍历比较
第一轮比较
- let i = 0,遍历newChildren,将newChildren[i]与oldFiber比较,判断DOM节点是否可复用;
JSX:newChildren[i]
currentFiber:oldFiber - 如果可复用,i++,继续比较newChildren[i]与oldFiber.sibling,可以复用则继续遍历;
- 如果不可复用,分两种情况:
a. key不同导致不可复用,立即跳出整个遍历,第一轮遍历结束;
b. key相同type不同导致不可复用,会将oldFiber标记mutation为DELETION,并继续遍历; - 如果newChildren遍历完(即 i === newChildren.length - 1 )或者oldFiber遍历完(即oldFiber.sibling === null),跳出遍历,第一轮遍历结束;
// 更新前
<li key="0">0</li>
<li key="1">1</li>
<li key="2">2</li>// 更新后
<li key="0">0</li>
<li key="2">1</li>
<li key="1">2</li>// 第一个节点可复用,遍历到key === 2的节点发现key改变,不可复用
// 跳出遍历,等待第二轮遍历处理// oldFiber: key === 1、key === 2未遍历
// newChildren剩下key === 2、key === 1未遍历
// 更新前
<li key="0" className="a">0</li>
<li key="1" className="b">1</li>// 更新后 情况1 —— newChildren与oldFiber都遍历完
<li key="0" className="aa">0</li>
<li key="1" className="bb">1</li>// 更新后 情况2 —— newChildren没遍历完,oldFiber遍历完
// newChildren剩下 key==="2" 未遍历
<li key="0" className="aa">0</li>
<li key="1" className="bb">1</li>
<li key="2" className="cc">2</li>// 更新后 情况3 —— newChildren遍历完,oldFiber没遍历完
// oldFiber剩下 key==="1" 未遍历
<li key="0" className="aa">0</li>
第二轮比较
-
newChildren和oldFiber都遍历完了,针对单一节点标记mutation,需要发生变化的元素记录在render阶段中,加update更新
-
newChildren剩下了,oldFiber没剩下,意味着新增了
将剩余的reset newChildren
直接添加到workInProgress Fiber
新增元素打标,将mutation
记为Placement
-
newChildren 没剩下 oldFiber 剩下了,意味着删除了
在workInProgress Fiber
中将旧的循环遍历掉,标记mutation
是DELETION
-
newChildren和oldFiber都剩下了
第二轮遍历:
const exisitingChildren = map(),通过map.get获取oldFiber剩下的所有存在existingChildren中- key:oldFiber中的key
- value:oldFiber中的value
遍历 newChildren 剩下的
exisitingChildren.has(newChildren[i].key),有的话获取这个元素,然后删除掉
lastPlacedIndex:最后一个可复用的节点,再当前oldFiber的索引位置
Update 状态更新
触发状态更新的方式
- 初始化的render
- setState
- useState
- forceUpdate
进行状态更新时候会创建一个Update 对象
,存储变更相关联的内容
包含到对应的fiber
,在beginWork
的过程中,找到这个fiber
,记录到当前更新的数组队列updateQueue
里
Update是在render beginWork
找到要更新的元素,Update置入
要更新的节点中,去触发它的state
// 一次更新的内容
const update: Update<*> = {eventTime, //获取当前的执行时间,判断执行更新的耗时lane, //优先级任务suspenseConfig, tag: UpdateState, //包裹住更新的状态,updateState | ReplaceState | forceUpdatepayload: null, //不同的更新元素带有的参数是什么callback: null,next: null, // 也是一个链表,下一次更新的内容
};
//一次更新的 update1 next->update2 next->update3
//div1 div2
fiber 节点 updateQueue指代的是div1,div2的变化
//一个更新的fiber的节点
const queue: UpdateQueue<State> = {baseState: fiber.memoizedState, //fiber中本身的statefirstBaseUpdate: null, //第一个更新的lastBaseUpdate: null, //最后一个更新的shared: {pending: null, //关联链表的方式,第一个更新,第二个更新,...最后一个更新,通过这个来关联的},effects: null,};
pending候车的上车
先上u3
这都是在render中做的,进入到commit阶段后,不管是谁,都不能被中断了,因为都已经在视图中了
因此,说的 异步可中断,说的都是在内存中能够做到的事情
u2优先级高于u1
但是链表:u1 — u2 这个顺序始终不会变
也就意味着,由于优先级,先执行的是u2,然后再执行一次 u1 和 u2。由此,高优先级的任务可能会触发两次
Concurrent Mode
协调模式
- Fiber 异步可中断
- Scheduler 协调器,结合可分片,异步可中断
- lane 优先级
- 优先级不同
- 优先级表达的方式 batch批次执行
- 方便计算
划分二进制31位内容
相关文章:
React进阶之React核心源码解析(二)
React核心源码解析 diff单一节点比较diff多节点比较diff两轮遍历比较第一轮比较第二轮比较 Update 状态更新Concurrent Mode diff 一共两个阶段 render:内存中的更新,主要是通过递归的过程,来将react变化的部分,在内存中找到哪些…...
八、OSG学习笔记-
前一章节: 七、OSG学习笔记-碰撞检测-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145558132?spm1001.2014.3001.5501 一、了解OSG图元加载显示流程 本章节代码: OsgStudy/wids CuiQingCheng/OsgStudy - 码云 - 开源中国https:…...
Python实现随机森林(Random Forest)算法
随机森林(Random Forest)是一种集成学习方法,通过构建多个决策树并结合它们的预测结果来提高模型的准确性和稳定性。下面是一个使用Python实现随机森林算法的示例。我们将使用scikit-learn库,它提供了方便的接口来实现随机森林。 …...
平方数列与立方数列求和的数学推导
先上结论: 平方数列求和公式为: S 2 ( n ) n ( n 1 ) ( 2 n 1 ) 6 S_2(n) \frac{n(n1)(2n1)}{6} S2(n)6n(n1)(2n1) 立方数列求和公式为: S 3 ( n ) ( n ( n 1 ) 2 ) 2 S_3(n) \left( \frac{n(n1)}{2} \right)^2 S3(n)(2n(n1)…...
new和malloc的区别
new malloc流程 new new流程 调用operator new 分配内存:在free store 生成对象 free store 可能在 堆 / 自定义的地方 可以认为虚拟内存到物理内存的映射关系早已完成 若分配内存失败(内存空间不够),抛出std::bad_alloc 异常…...
JVM——垃圾回收算法
目录 垃圾回收算法 评价标准: 标记-清除算法: 复制算法: 标记-整理算法: 分代GC: arthas查看分代之后的内存情况: 垃圾回收算法 java是如何实现垃圾回收的呢?简单来说,垃圾回…...
算法日记16:SC68 联通块问题(并查集)
一、题目: 二、题解: 1、看到求联通块问题,我们可以考虑使用DFS/并查集(在这里我们仅介绍并查集) 2、什么是并查集? 2.1:初始化:对于每一个点,我们都对其进行初始化操作pre[i]i pre[i]表示i的…...
Unity-Mirror网络框架-从入门到精通之Pong示例
文章目录 前言示例介绍NetworkManagerPongBallPlayer总结前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开源网络框架,专为多人游戏开发设计…...
c++ 多线程知识汇总
一、std::thread std::thread 是 C11 引入的标准库中的线程类,用于创建和管理线程 1. 带参数的构造函数 template <class F, class... Args> std::thread::thread(F&& f, Args&&... args);F&& f:线程要执行的函数&…...
探索 Text-to-SQL 技术:从自然语言到数据库查询的桥梁
亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、Java 与 Python 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在未来…...
Java NIO ByteBuffer 详解
什么是 ByteBuffer ByteBuffer 是 Buffer 的一个具体实现,专门用于存储和操作字节数据。它提供了高效的、基于内存的 I/O 数据处理方式。 Buffer 类是构建 Java NIO 的基础,其中 ByteBuffer 类是 Buffer 子类中最受欢迎的。这是因为字节类型是最通用的…...
【机器学习】简单线性回归算法及代码实现
线性回归算法 一、摘要二、线性回归算法概述三、损失函数的定义和衡量标准四、简单线性回归的求解和应用五、机器学习算法一般求解思路 一、摘要 本文讲解了线性回归算法的基础知识和应用,强调线性回归主要用于解决回归问题。通过分析房产价格与房屋面积的关系&…...
【前端开发】query参数和params参数的区别
在Web开发中,query参数(URL查询参数)和params参数(路由参数)是两种不同的URL传参方式,它们的核心区别如下: 一、 位置不同 query参数params参数位置URL中?之后,用&连接多个参数…...
人工智能数学基础学习PPT
学习视频:人工智能 -数学基础 文章目录 1.简介1.函数2.极限3.无穷小与无穷大4.连续性与导数5.偏导数6.方向导数7.梯度 2.微积分1.微积分基本想法2.微积分的解释3.定积分4.定积分性质5.牛顿-莱布尼茨公式 3.泰勒公式与拉格朗日1.泰勒公式2.一点一世界3.阶数的作用4.…...
企业文件防泄密软件哪个好?
在企业文件防泄密软件领域,天锐绿盾和中科数安都是备受认可的品牌,它们各自具有独特的特点和优势。 以下是对这两款软件的详细比较: 天锐绿盾 功能特点 集成性强:集成了文件加密、数据泄露防护DLP、终端安全管理、行为审计等数据安…...
美丽 百褶裙提示词 + MD
MD 参考教程:Marvelous Designer零基础教学,MD布料制作-百褶裙建模制作,次世代教学_哔哩哔哩_bilibili 【MD新手教程】30分钟教会你制作百褶裙,Marvelous Designer超简单入门案例教程_哔哩哔哩_bilibili 【c4d技术解析】MD百褶裙…...
解释和对比“application/octet-stream“与“application/x-protobuf“
介绍 在现代 Web 和分布式系统的开发中,数据的传输和交换格式扮演着关键角色。为了确保数据在不同系统之间的传输过程中保持一致性,MIME 类型(Multipurpose Internet Mail Extensions)被广泛应用于描述数据的格式和内容类型。在 …...
基于YALMIP和cplex工具箱的微电网最优调度算法matlab仿真
目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 系统建模 4.2 YALMIP工具箱 4.3 CPLEX工具箱 5.完整工程文件 1.课题概述 基于YALMIP和cplex工具箱的微电网最优调度算法matlab仿真。通过YALMIP和cplex这两个工具箱,完成微电网的最优调…...
AI前端开发技能提升与ScriptEcho:拥抱AI时代的前端开发新范式
随着人工智能技术的飞速发展,AI前端开发岗位对技能的要求也水涨船高。越来越多的企业需要具备AI相关知识和高级前端开发能力的工程师,这使得传统的前端开发模式面临着巨大的挑战。如何提升开发效率,降低人力成本,成为了摆在所有前…...
LeetCode题解:2690. 无穷方法对象,Proxy
Problem: 2690. 无穷方法对象 思路 这个问题的核心在于创建一个对象,该对象能够响应对其任何方法的调用,并返回调用的方法名称。为了实现这一点,我们可以利用 JavaScript 中的 Proxy 对象。Proxy 对象允许我们自定义对象的基本操作ÿ…...
Python中的HTTP客户端库:httpx与request | python小知识
Python中的HTTP客户端库:httpx与request | python小知识 在Python中,发送HTTP请求和处理响应是网络编程的基础。requests和httpx是两个常用的HTTP库,它们都提供了简洁易用的API来发送HTTP请求。然而,httpx作为新一代的HTTP客户端…...
RabbitMQ使用guest登录提示:User can only log in via localhost
guest用户默认是无法使用远程访问的,生产环境建议直接在对应服务器登录使用。 1、通过创建新增用户并赋予权限实现远程登录 添加新用户 rabbitmqctl add_user zjp zjp 设置管理员 rabbitmqctl set_user_tags zjp administrator 设置新用户的权限 rabbitmqctl…...
#渗透测试#批量漏洞挖掘#Crocus系统—Download 文件读取
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
基于Matlab实现六自由度机械臂正逆运动仿真(源码)
在机器人技术领域,六自由度机械臂是一种广泛应用的设备,它可以实现空间中的位置和姿态控制。本项目聚焦于六自由度机械臂的正逆运动学仿真,利用MATLAB2016b作为开发工具,旨在深入理解并掌握机械臂的工作原理和运动控制。 正运动学…...
亚信安全正式接入DeepSeek
亚信安全致力于“数据驱动、AI原生”战略,早在2024年5月,推出了“信立方”安全大模型、安全MaaS平台和一系列安全智能体,为网络安全运营、网络安全检测提供AI技术能力。自2024年12月DeepSeek-V3发布以来,亚信安全人工智能实验室利…...
Django 创建第一个项目
Django 创建第一个项目 引言 Django 是一个高级的 Python Web 框架,它鼓励快速开发和干净、实用的设计。本指南将带您从头开始创建一个简单的 Django 项目,以便您能够熟悉 Django 的基本结构和概念。 准备工作 在开始之前,请确保您已经安装了 Python 和 Django。以下是安…...
RL基础概念
RL意味着模型从真实世界中获取反馈,根据策略调整参数,以达到最大化反馈的优化算法; 强化学习的核心在于:1.试错(因为仅凭reward无法得到明确的优化方向,所以需要不断多尝试);2.延迟奖…...
像取快递一样取文件?
看到一个很有意思的项目,像我们做软件分享的感觉会有用,就是现在服务器费用太贵了,如果自建的话感觉不是很值得。 FileCodeBox FileCodeBox 是一个轻量级的文件分享系统,它基于匿名口令分享文本和文件,无需注册登录&…...
Jenkins 新建配置Pipeline任务 三
Jenkins 新建配置Pipeline任务 三 一. 登录 Jenkins 网页输入 http://localhost:8080 输入账号、密码登录 一个没有创建任务的空 Jenkins 二. 创建 任务 图 NewItem 界面左上角 New Item 图NewItemSelect 1.Enter an item name:输入任务名 2.Select an ite…...
React 前端框架搭建与解析
React 前端框架搭建与解析 一、 概述 React 是 Facebook 开源的用于构建用户界面的 JavaScript 库,以其组件化、声明式编程范式以及高效的虚拟 DOM 渲染机制,成为当今最流行的前端框架之一。本文将带领你从零开始搭建一个 React 开发环境,并深入解析其核心概念。 二、 环…...
像指针操作、像函数操作的类
像指针一样的类。把一个类设计成像一个指针。什么操作符运用到指针上? 使用标准库的时候,里面有个很重要的东西叫容器。容器本身一定带着迭代器。迭代器作为另外一种智能指针。迭代器指向容器里的一个元素。迭代器用来遍历容器。 _list_iterator是链表迭…...
15.Python网络编程:进程池、进程间通信、多线程、进程和线程区别、网络通信、端口、IP地址、socket、UDP、TCP、http
1. 进程池(Process Pool) 进程池是通过将多个进程放入池中管理来避免频繁地创建和销毁进程,提高效率。Python 提供了 multiprocessing.Pool 类来实现进程池,它可以用于并行计算任务。 示例:使用进程池 from multipr…...
Ubuntu启动geteck/jetlinks实战:Docker启动
参考: JetLinks 物联网基础平台 安装Docker Ubuntu下载安装Docker-Desktop-CSDN博客 sudo apt install -y docker-compose 下载源码 git clone https://github.com/jetlinks/jetlinks-community.git cd jetlinks-community 启动 cd docker/…...
Newton 差商插值多项式
Newton 差商插值多项式 根据差商定义,把 x x x 看成[ a , b ] a,b] a,b]上一点,可得 f ( x ) f ( x 0 ) f [ x , x 0 ] ( x − x 0 ) f(x)f(x_0)f[x,x_0](x-x_0) f(x)f(x0)f[x,x0](x−x0) f [ x , x 0 ] f [ x 0 , x 1 ] f [ x , x 0 , x 1…...
ubuntu下ollama/vllm两种方式在本地部署Deepseek-R1
1.前言 今年过年,deepseek一下子爆火,导致我前段时间好好用的官网直接挤爆了,一直转圈圈到没心思过了,天天挂热搜,直接导致我的科研工作受阻(dog),好吧,话不多说,看看怎么在本地部署deepseek丝滑享受以及白嫖一下api体验>_<! 部署环境: 系统:ubuntu22.04 显…...
如何使用ps批量去除固定位置水印
使用 Photoshop 批量去除固定位置的水印,有几种方法可以实现自动化,具体取决于水印的复杂程度和你对 Photoshop 的熟悉程度: 1. 动作(Actions) 批处理(Batch): 这是最常用的方法&…...
基于 STM32 的病房监控系统
标题:基于 STM32 的病房监控系统 内容:1.摘要 基于 STM32 的病房监控系统摘要:本系统采用 STM32 微控制器作为核心,通过传感器实时监测病房内的环境参数,如温度、湿度、光照等,并将数据上传至云端服务器。医护人员可以通过手机或…...
Windows部署deepseek-r1
安装Ollama 访问Ollama下载页,选择对应的操作系统进行下载 运行OllamaSetup,进行安装 任务栏出现Ollama图标,运行正常 cmd查看Ollama版本 C:\Users\PC>ollama -v ollama version is 0.5.7 部署模型 deepseek 可访问deepseek模型页,切…...
CCFCSP第34次认证第一题——矩阵重塑(其一)
第34次认证第一题——矩阵重塑(其一) 官网链接 时间限制: 1.0 秒 空间限制: 512 MiB 相关文件: 题目目录(样例文件) 题目背景 矩阵(二维)的重塑(reshap…...
webpack打包优化策略
1. 减少打包体积 减少打包文件的大小是为了提高加载速度,降低网络带宽消耗,提升用户体验。常见的减少打包体积的优化策略包括: 代码分割(Code Splitting):将代码拆分成多个小文件,让浏览器按需…...
八股文-2025-02-12
BFC BFC属于普通流。BFC全称是Block Formatting Context,意思就是块级格式化上下文。你可以把BFC看做元素的一个属性,当元素拥有BFC属性,这个元素就可以看作是隔离了的独立容器,容器里边的元素不会影响到容器外部的元素.https://b…...
部门管理(体验,最原始方法来做,Django+mysql)
本人初学,写完代码在此记录和复盘 在创建和注册完APP之后(我的命名是employees),编写models.py文件创建表 手动插入了几条数据 1.部门查询 urls.py和views.py在编写之前,都要注意导入对应的库 urls.py:…...
联想拯救者Y9000银河麒麟系统安装Nvidia 4060显卡驱动
查了好多资料, 发现银河麒麟的资料较少, 只能自己试验了, 如有帮助, 点个赞吧~~ 前提: 本人笔记本是联想拯救者Y9000, 独立显卡 Nvidia4060, 主机系统是银河麒麟V10 (2403), 笔记本处于联网状态ÿ…...
深入解析 STM32 GPIO:结构、配置与应用实践
理解 GPIO 的工作原理和配置方法是掌握 STM32 开发的基础,后续的外设(如定时器、ADC、通信接口)都依赖于 GPIO 的正确配置。 目录 一、GPIO 的基本概念 二、GPIO 的主要功能 三、GPIO 的内部结构 四、GPIO 的工作模式 1. 输入模式 2. 输…...
突破数据壁垒,动态住宅代理IP在数据采集中的高效应用
在当今数字化时代,数据已经成为企业和个人决策的重要依据。无论是市场调研、竞争分析,还是价格监控、SEO优化,数据采集都扮演着至关重要的角色。然而,随着技术发展与网络安全措施的日益严格,传统的数据采集方式面临着前…...
Spring 项目接入 DeepSeek,分享两种超简单的方式!
⭐自荐一个非常不错的开源 Java 面试指南:JavaGuide (Github 收获148k Star)。这是我在大三开始准备秋招面试的时候创建的,目前已经持续维护 6 年多了,累计提交了 5600 commit ,共有 550 多位贡献者共同参与…...
SSE与Websocket详解,SSE实现对话框流式输出
SSE详解 SSE(Server-Sent Events)是一种在Web应用中实现单向实时通信的技术,它允许服务器主动向客户端发送更新,而无需客户端不断发起请求。SSE基于HTTP协议,利用HTTP的长连接特性,通过浏览器向服务器发送一个HTTP请求,建立一条持久化的连接,然后服务器可以通过这条连…...
Shell脚本笔记
Linux其他命令 Shell脚本笔记...
Hydra主配置文件和模块化配置管理
在 Hydra 中,我们可以使用 defaults 关键字 在主配置文件 config.yaml 中加载多个子配置文件,从而实现 模块化配置管理。这在深度学习、超参数优化、数据预处理等场景下非常有用。 1️⃣ 配置文件目录结构 假设我们有一个深度学习训练项目,…...
oracle dbms_sqltune 使用
创建测试表 CREATE TABLE test_table (id NUMBER PRIMARY KEY,event_date DATE,value NUMBER );插入测试数据 DECLAREi NUMBER; BEGINFOR i IN 1..1000000 LOOPINSERT INTO test_table (id, event_date, value)VALUES (i, SYSDATE - MOD(i, 365), DBMS_RANDOM.VALUE(1, 1000)…...