react之Effect的生命周期

第四章 - 脱围机制

响应式 Effect 的生命周期

Effect与组件有不同的生命周期。组件可以挂载,更新或卸载。Effect只能做两件事:开始同步某些东西,然后停止同步它。如果Effect依赖于随时间变化的props 和 state,这个循环可能会发生多次。React提供了代码检查规则来检查是否正确地指定了Effect的依赖项,这能使Effect与最新的props和state保持同步。

Effect的生命周期

每个react组件都经历相同的生命周期:

  • 当组件被添加到屏幕上,它会进行组件的挂载
  • 当组件接收到新的props或state时,通常是作为对交互的响应,它会进行组件的更新
  • 当组件从屏幕上移除时,它会进行组件的卸载

这是一种很好的思考组件的方法,但并不适用于Effect。相反,尝试从组件生命周期中脱出来独立思考 Effect。Effect 描述了如何将外部系统与当前的 props 和 state 同步。随着代码的变化,同步的频率可能会增加或减少。

为了说明这一点,考虑下面这个示例。Effect 将组件连接到聊天服务器:

const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, [roomId]);// ...
}

Effect的主体部分指定了如何开始同步,Effect返回的清理函数指定了如何停止同步:

你可能会直观地认为当组件挂载时 React 会 开始同步,而当组件卸载时会 停止同步。然而,事情并没有这么简单!有时,在组件保持挂载状态的同时,可能还需要 多次开始和停止同步。

让我们来看看 为什么 这是必要的、何时 会发生以及 如何 控制这种行为。

注意

有些 Effect 根本不返回清理函数。在大多数情况下,可能希望返回一个清理函数,但如果没有返回,React 将表现得好像返回了一个空的清理函数。

为什么同步可能需要多次进行

想象一下,这个 ChatRoom 组件接收 roomId 属性,用户可以在下拉菜单中选择。假设初始时,用户选择了 "general" 作为 roomId。应用程序会显示 "general" 聊天室:

const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId /* "general" */ }) {// ...return <h1>欢迎来到 {roomId} 房间!</h1>;
}

在 UI 显示之后,React 将运行 Effect 来 开始同步。它连接到 "general" 聊天室:

function ChatRoom({ roomId /* "general" */ }) {useEffect(() => {const connection = createConnection(serverUrl, roomId); // 连接到 "general" 聊天室connection.connect();return () => {connection.disconnect(); // 断开与 "general" 聊天室的连接};}, [roomId]);// ...

到目前为止,一切都很顺利。

之后,用户在下拉菜单中选择了不同的房间(例如 "travel" )。首先,React 会更新 UI:

思考接下来应该发生什么。用户在界面中看到 "travel" 是当前选定的聊天室。然而,上次运行的 Effect 仍然连接到 "general" 聊天室。roomId 属性已经发生了变化,所以之前 Effect 所做的事情(连接到 "general" 聊天室)不再与 UI 匹配。

此时,你希望 React 执行两个操作:

  1. 停止与旧的 roomId 同步(断开与 "general" 聊天室的连接)
  2. 开始与新的 roomId 同步(连接到 "travel" 聊天室)

幸运的是,你已经教会了 React 如何执行这两个操作!Effect 的主体部分指定了如何开始同步,而清理函数指定了如何停止同步。现在,React 只需要按照正确的顺序和正确的 props 和 state 来调用它们。让我们看看具体是如何实现的。

react如何重新同步 Effect

回想一下,ChatRoom 组件已经接收到了 roomId 属性的新值。之前它是 "general",现在变成了 "travel"。React 需要重新同步 Effect,以重新连接到不同的聊天室。

为了 停止同步,React 将调用 Effect 返回的清理函数,该函数在连接到 "general" 聊天室后返回。由于 roomId 为 "general",清理函数将断开与 "general" 聊天室的连接:

然后,React 将运行在此渲染期间提供的 Effect。这次,roomId 为 "travel",因此它将 开始同步 到 "travel" 聊天室(直到最终也调用了清理函数)

每当组件使用不同的 roomId 重新渲染后,Effect 将重新进行同步。例如,假设用户将 roomId 从 "travel" 更改为 "music"。React 将再次通过调用清理函数 停止同步 Effect(断开与 "travel" 聊天室的连接)。然后,它将通过使用新的 roomId 属性再次运行 Effect 的主体部分 开始同步(连接到 "music" 聊天室)。

最后,当用户切换到不同的屏幕时,ChatRoom 组件将被卸载。现在没有必要保持连接了。React 将 最后一次停止同步 Effect,并从 "music" 聊天室断开连接。

从Effect的角度思考

让我们总结一下从 ChatRoom 组件的角度所发生的一切:

  1. ChatRoom 组件挂载,roomId 设置为 "general"
  2. ChatRoom 组件更新,roomId 设置为 "travel"
  3. ChatRoom 组件更新,roomId 设置为 "music"
  4. ChatRoom 组件卸载

在组件生命周期的每个阶段,Effect 执行了不同的操作:

  1. Effect 连接到了 "general" 聊天室
  2. Effect 断开了与 "general" 聊天室的连接,并连接到了 "travel" 聊天室
  3. Effect 断开了与 "travel" 聊天室的连接,并连接到了 "music" 聊天室
  4. Effect 断开了与 "music" 聊天室的连接

现在让我们从 Effect 本身的角度来思考所发生的事情:

  useEffect(() => {// Effect 连接到了通过 roomId 指定的聊天室...const connection = createConnection(serverUrl, roomId);connection.connect();return () => {// ...直到它断开连接connection.disconnect();};}, [roomId]);

这段代码的结构可能会将所发生的事情看作是一系列不重叠的时间段:

  1. Effect 连接到了 "general" 聊天室(直到断开连接)
  2. Effect 连接到了 "travel" 聊天室(直到断开连接)
  3. Effect 连接到了 "music" 聊天室(直到断开连接)

之前,你是从组件的角度思考的。当你从组件的角度思考时,很容易将 Effect 视为在特定时间点触发的“回调函数”或“生命周期事件”,例如“渲染后”或“卸载前”。这种思维方式很快变得复杂,所以最好避免使用。

相反,始终专注于单个启动/停止周期。无论组件是挂载、更新还是卸载,都不应该有影响。只需要描述如何开始同步和如何停止。如果做得好,Effect 将能够在需要时始终具备启动和停止的弹性。

这可能会让你想起当编写创建 JSX 的渲染逻辑时,并不考虑组件是挂载还是更新。描述的是应该显示在屏幕上的内容,而 React 会 解决其余的问题。

React 如何知道需要重新进行 Effect 的同步

你可能想知道 React 是如何知道在 roomId 更改后需要重新同步 Effect。这是因为 你告诉了 React 它的代码依赖于 roomId,通过将其包含在 依赖列表 中。

function ChatRoom({ roomId }) { // roomId 属性可能会随时间变化。useEffect(() => {const connection = createConnection(serverUrl, roomId); // 这个 Effect 读取了 roomIdconnection.connect();return () => {connection.disconnect();};}, [roomId]); // 因此,你告诉 React 这个 Effect "依赖于" roomId

下面是它的工作原理:

  1. 你知道 roomId 是 prop,这意味着它可能会随着时间的推移发生变化。
  2. 你知道 Effect 读取了 roomId(因此其逻辑依赖于可能会在之后发生变化的值)。
  3. 这就是为什么你将其指定为 Effect 的依赖项(以便在 roomId 发生变化时重新进行同步)。

每次在组件重新渲染后,React 都会查看传递的依赖项数组。如果数组中的任何值与上一次渲染时在相同位置传递的值不同,React 将重新同步 Effect。

例如,如果在初始渲染时传递了 ["general"],然后在下一次渲染时传递了 ["travel"],React 将比较 "general" 和 "travel"。这些是不同的值(使用 Object.is 进行比较),因此 React 将重新同步 Effect。另一方面,如果组件重新渲染但 roomId 没有发生变化,Effect 将继续连接到相同的房间。

每个 Effect 表示一个独立的同步过程

抵制将与 Effect 无关的逻辑添加到已经编写的 Effect 中,仅仅因为这些逻辑需要与 Effect 同时运行。例如,假设你想在用户访问房间时发送一个分析事件。你已经有一个依赖于 roomId 的 Effect,所以你可能会想要将分析调用添加到那里:

function ChatRoom({ roomId }) {useEffect(() => {logVisit(roomId);const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, [roomId]);// ...
}

但是想象一下,如果以后给这个 Effect 添加了另一个需要重新建立连接的依赖项。如果这个 Effect 重新进行同步,它将为相同的房间调用 logVisit(roomId),而这不是你的意图。记录访问行为是 一个独立的过程,与连接不同。将它们作为两个单独的 Effect 编写:

function ChatRoom({ roomId }) {useEffect(() => {logVisit(roomId);}, [roomId]);useEffect(() => {const connection = createConnection(serverUrl, roomId);// ...}, [roomId]);// ...
}

代码中的每个 Effect 应该代表一个独立的同步过程。

在上面的示例中,删除一个 Effect 不会影响另一个 Effect 的逻辑。这表明它们同步不同的内容,因此将它们拆分开是有意义的。另一方面,如果将一个内聚的逻辑拆分成多个独立的 Effects,代码可能会看起来更加“清晰”,但 维护起来会更加困难。这就是为什么你应该考虑这些过程是相同还是独立的,而不是只考虑代码是否看起来更整洁。

Effect会响应于响应式的值

Effect 读取了两个变量(serverUrl 和 roomId),但是只将 roomId 指定为依赖项:

const serverUrl = 'https://localhost:1234';function ChatRoom({ roomId }) {useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, [roomId]);// ...}

为什么 serverUrl 不需要作为依赖项呢?

这是因为 serverUrl 永远不会因为重新渲染而发生变化。无论组件重新渲染多少次以及原因是什么,serverUrl 都保持不变。既然 serverUrl 从不变化,将其指定为依赖项就没有意义。毕竟,依赖项只有在随时间变化时才会起作用!

另一方面,roomId 在重新渲染时可能会不同。在组件内部声明的 props、state 和其他值都是 响应式 的,因为它们是在渲染过程中计算的,并参与了 React 的数据流。

如果 serverUrl 是状态变量,那么它就是响应式的。响应式值必须包含在依赖项中:

function ChatRoom({ roomId }) { // Props 随时间变化const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // State 可能随时间变化useEffect(() => {const connection = createConnection(serverUrl, roomId); // Effect 读取 props 和 stateconnection.connect();return () => {connection.disconnect();};}, [roomId, serverUrl]); // 因此,你告诉 React 这个 Effect "依赖于" props 和 state// ...
}

没有依赖项的Effect 的含义

如果将 serverUrl 和 roomId 都移出组件会发生什么?

const serverUrl = 'https://localhost:1234';const roomId = 'general';function ChatRoom() {useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, []); // ✅ 声明的所有依赖// ...}

现在 Effect 的代码不使用任何响应式值,因此它的依赖可以是空的 ([])。

从组件的角度来看,空的 [] 依赖数组意味着这个 Effect 仅在组件挂载时连接到聊天室,并在组件卸载时断开连接。(请记住,在开发环境中,React 仍会 额外执行一次 来对逻辑进行压力测试。)

然而,如果你 从 Effect 的角度思考,根本不需要考虑挂载和卸载。重要的是,你已经指定了 Effect 如何开始和停止同步。目前,它没有任何响应式依赖。但是,如果希望用户随时间改变 roomId 或 serverUrl(它们将变为响应式),Effect 的代码不需要改变。只需要将它们添加到依赖项中即可。

在组件主体中声明的所有变量都是响应式的

Props 和 state 并不是唯一的响应式值。从它们计算出的值也是响应式的。如果 props 或 state 发生变化,组件将重新渲染,从中计算出的值也会随之改变。这就是为什么 Effect 使用的组件主体中的所有变量都应该在依赖列表中。

假设用户可以在下拉菜单中选择聊天服务器,但他们还可以在设置中配置默认服务器。假设你已经将设置状态放入了 上下文,因此从该上下文中读取 settings。现在,可以根据 props 中选择的服务器和默认服务器来计算 serverUrl:

function ChatRoom({ roomId, selectedServerUrl }) { // roomId 是响应式的const settings = useContext(SettingsContext); // settings 是响应式的const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl 是响应式的useEffect(() => {const connection = createConnection(serverUrl, roomId); // Effect 读取了 roomId 和 serverUrlconnection.connect();return () => {connection.disconnect();};}, [roomId, serverUrl]); // 因此,当它们中的任何一个发生变化时,它需要重新同步!// ...
}

在这个例子中,serverUrl 不是 prop 或 state 变量。它是在渲染过程中计算的普通变量。但是它是在渲染过程中计算的,所以它可能会因为重新渲染而改变。这就是为什么它是响应式的。

组件内部的所有值(包括 props、state 和组件体内的变量)都是响应式的。任何响应式值都可以在重新渲染时发生变化,所以需要将响应式值包括在 Effect 的依赖项中。

换句话说,Effect 对组件体内的所有值都会“react”。

深入讨论 - 全局变量或可变值可以作为依赖项吗?

可变值(包括全局变量)不是响应式的。

例如,像 location.pathname 这样的可变值不能作为依赖项。它是可变的,因此可以在 React 渲染数据流之外的任何时间发生变化。更改它不会触发组件的重新渲染。因此,即使在依赖项中指定了它,React 也无法知道在其更改时重新同步 Effect。这也违反了 React 的规则,因为在渲染过程中读取可变数据(即在计算依赖项时)会破坏 纯粹的渲染。相反,应该使用 useSyncExternalStore 来读取和订阅外部可变值。

另外,像 ref.current 或从中读取的值也不能作为依赖项。useRef 返回的 ref 对象本身可以作为依赖项,但其 current 属性是有意可变的。它允许 跟踪某些值而不触发重新渲染。但由于更改它不会触发重新渲染,它不是响应式值,React 不会知道在其更改时重新运行 Effect。

正如你将在本页面下面学到的那样,检查工具将自动检查这些问题。

React 会验证是否将每个响应式值都指定为了依赖项

如果检查工具 配置了 React,它将检查 Effect 代码中使用的每个响应式值是否已声明为其依赖项。例如,以下示例是一个 lint 错误,因为 roomId 和 serverUrl 都是响应式的:

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';function ChatRoom({ roomId }) { // roomId 是响应式的const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl 是响应式的useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => connection.disconnect();}, []); // <-- 这里有些问题!return (<><label>服务器 URL:{' '}<inputvalue={serverUrl}onChange={e => setServerUrl(e.target.value)}/></label><h1>欢迎来到 {roomId} 房间!</h1></>);
}export default function App() {const [roomId, setRoomId] = useState('general');return (<><label>选择聊天室:{' '}<selectvalue={roomId}onChange={e => setRoomId(e.target.value)}><option value="general">所有</option><option value="travel">旅游</option><option value="music">音乐</option></select></label><hr /><ChatRoom roomId={roomId} /></>);
}

这可能看起来像是 React 错误,但实际上 React 是在指出代码中的 bug。roomId 和 serverUrl 都可能随时间改变,但忘记了在它们改变时重新同步 Effect。即使用户在 UI 中选择了不同的值,仍然保持连接到初始的 roomId 和 serverUrl。

要修复这个 bug,请按照检查工具的建议将 roomId 和 serverUrl 作为 Effect 的依赖进行指定:

function ChatRoom({ roomId }) { // roomId 是响应式的const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl 是响应式的useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, [serverUrl, roomId]); // ✅ 声明的所有依赖// ...}

在上面的沙盒中尝试这个修复方法。验证一下是否消除了检查工具的错误,并且在需要时聊天会重新连接。

注意

在某些情况下,React 知道 一个值永远不会改变,即使它在组件内部声明。例如,从 useState 返回的 set 函数和从 useRef 返回的 ref 对象是 稳定的 ——它们保证在重新渲染时不会改变。稳定值不是响应式的,因此可以从列表中省略它们。包括它们是允许的:它们不会改变,所以无关紧要。

当你不想进行重新同步时该怎么办

在上一个示例中,通过将 roomId 和 serverUrl 列为依赖项来修复了 lint 错误。

然而,可以通过向检查工具“证明”这些值不是响应式值,即它们 不会 因为重新渲染而改变。例如,如果 serverUrl 和 roomId 不依赖于渲染并且始终具有相同的值,可以将它们移到组件外部。现在它们不需要成为依赖项:

const serverUrl = 'https://localhost:1234'; // serverUrl 不是响应式的const roomId = 'general'; // roomId 不是响应式的function ChatRoom() {useEffect(() => {const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, []); // ✅ 声明的所有依赖// ...}

也可以将它们 移动到 Effect 内部。它们不是在渲染过程中计算的,因此它们不是响应式的:

function ChatRoom() {useEffect(() => {const serverUrl = 'https://localhost:1234'; // serverUrl 不是响应式的const roomId = 'general'; // roomId 不是响应式的const connection = createConnection(serverUrl, roomId);connection.connect();return () => {connection.disconnect();};}, []); // ✅ 声明的所有依赖// ...}

Effect 是一段响应式的代码块。它们在读取的值发生变化时重新进行同步。与事件处理程序不同,事件处理程序只在每次交互时运行一次,而 Effect 则在需要进行同步时运行。

不能“选择”依赖项。依赖项必须包括 Effect 中读取的每个 响应式值。代码检查工具会强制执行此规则。有时,这可能会导致出现无限循环的问题,或者 Effect 过于频繁地重新进行同步。不要通过禁用代码检查来解决这些问题!下面是一些解决方案:

  • 检查 Effect 是否表示了独立的同步过程。如果 Effect 没有进行任何同步操作,可能是不必要的。如果它同时进行了几个独立的同步操作,将其拆分为多个 Effect。
  • 如果想读取 props 或 state 的最新值,但又不想对其做出反应并重新同步 Effect,可以将 Effect 拆分为具有反应性的部分(保留在 Effect 中)和非反应性的部分(提取为名为 “Effect Event” 的内容)。阅读关于将事件与 Effect 分离的内容。
  • 避免将对象和函数作为依赖项。如果在渲染过程中创建对象和函数,然后在 Effect 中读取它们,它们将在每次渲染时都不同。这将导致 Effect 每次都重新同步。阅读有关从 Effect 中删除不必要依赖项的更多内容。
摘要
  • 组件可以挂载,更新和卸载
  • 每个Effect与周围组件有着独立的生命周期
  • 每个Effect描述了一个独立的同步过程们可以开始和停止
  • 在编写和读取Effect时,要独立地考虑每个Effect (如何开始和如何停止同步),而不是从组件的角度思考 (如何挂载,更新,卸载)
  • 在组件主体内声明的值是响应式的
  • 响应式值应该重新进行同步Effect,因为它们可以随着时间的推移而发生变化
  • 检查工具验证在Effect内部使用的所有响应式值都被指定为依赖项
  • 检查工具标记的所有错误都是合理的。总是有一个方法可以修复代码,同时不违反规则

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

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

相关文章

如何查看热门GPT应用?

1、登陆chatgpt 2、访问 https://chatgpt.com/gpts 3、在该界面&#xff0c;可以搜索并使用image generator, Write For Me&#xff0c;Language Teature等热门应用。

嵌入式C语言中结构体使用详解

各位开发者大家好,今天给大家分享一下,嵌入式C语言中结构体的使用方法。 第一个:内存对齐 内存对齐是指一个数据类型在内存中存放时,对其地址的要求。简单来说内存对齐就是使得其内存地址是该类型大小的整数倍,例如 double 类型的变量,其内存地址需要是8的倍数(double大…

Golang:使用bcrypt实现密码加密和和校验

bcrypt可以用于数据库中的用户密码保存&#xff0c;相比md5而言更加的安全可靠 文档 https://pkg.go.dev/golang.org/x/crypto/bcrypt 文档上给出了标准文档&#xff0c;这个库是下面这个文件描述的算法golang实现: https://www.usenix.org/legacy/event/usenix99/provos/p…

深入理解 Mysql 分层架构:从存储引擎到查询优化器的内部机制解析

一、基础架构 1.连接器 1.会先连接到这个数据库上&#xff0c;这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接 2.用户密码连接成功之后&#xff0c;会从权限表中拿出你的权限&#xff0c;后续操作权限都依赖于此时拿出的权限,这就意味着当链…

SVM兵王问题

1.流程 前面六个就是棋子的位置&#xff0c;draw就是逼和&#xff0c;后面的数字six就代表&#xff0c;白棋最少用六步就能将死对方。然后呢&#xff0c;可以看一下最后一个有几种情况&#xff1a; 2.交叉测试 leave one out&#xff1a; 留一个样本作测试集&#xff0c;其余…

Django 里的静态资源调用

静态资源&#xff1a;图片&#xff0c;CSS, JavaScript 一共有两种方法 第一种方法 在项目的文件夹里创建名为 static 文件夹 在该文件夹里&#xff0c;添加静态资源 在 settings.py 里添加路径 import os# Static files (CSS, JavaScript, Images) # https://docs.djan…

Oracle Graph 入门 - RDF 知识图谱

Oracle Graph 入门 - RDF 知识图谱 0. 引言1. 查看 RDF Semantic Graph 安装情况2. 创建一个语义网络4. 创建一个模型5. 加载 RDF 文件6. 配置 W3C 标准的 SPARQL 端点 0. 引言 Oracle Graph 的中文资料太少了&#xff0c;只能自己参考英文资料整理一篇吧。 Oracle 数据库包括…

搭建Harbor镜像仓库

前言 1、系统版本&#xff1a;CentOS9 2、harbor版本&#xff1a;v2.9.4 3、提前安装好docker和docker-compose&#xff0c;参考地址。我这里安装的版本是docker&#xff1a;26.1.3 docker-compose&#xff1a;v2.27.1 安装步骤 下载安装包 1、下载地址&#xff1a;ha…

[自动驾驶技术]-1 概述技术和法规

自动驾驶&#xff08;Autonomous Driving&#xff09;&#xff0c;也称为无人驾驶或自驾&#xff0c;是指通过计算机系统和传感器设备&#xff0c;自动驾驶汽车在没有人类干预的情况下能够感知环境并做出驾驶决策&#xff0c;从而实现车辆的自主行驶。 自动驾驶技术层级 自动…

fastadmin 树状菜单展开,合并;简要文件管理系统界面设计与实现

一&#xff0c;菜单合并效果图 源文件参考&#xff1a;fastadmin 子级菜单展开合并、分类父级归纳 - FastAdmin问答社区 php服务端&#xff1a; public function _initialize() {parent::_initialize();$this->model new \app\admin\model\auth\Filetype;$this->admin…

企业如何做好 SQL 质量管理?

研发人员写 SQL 操作数据库想必一定是一类基础且常见的工作内容。如何避免 “问题” SQL 流转到生产环境&#xff0c;保证数据质量&#xff1f;这值得被研发/DBA/运维所重视。 什么是 SQL 问题&#xff1f; 对于研发人员来说&#xff0c;在日常工作中&#xff0c;大部分都需要…

Jenkins - Pipeline Retry

Jenkins - Pipeline Retry 引言retryretry 实例 引言 日常运行自动化测试用例&#xff0c;通常是晚上定时启动 pipeline job&#xff0c;一个 pipeline 脚本可能会涉及到多个 Job, 最后 post 发邮件汇总测试 report。有时会遇到 Jenkins 环境问题导致某 Job 失败&#xff0c;第…

代码随想录算法训练营第三十六天 | 1005.K次取反后最大化的数组和、134.加油站、135.分发糖果

目录 1005.K次取反后最大化的数组和 思路 代码 代码 134.加油站 思路 代码 135.分发糖果 思路 代码 1005.K次取反后最大化的数组和 本题简单一些&#xff0c;估计大家不用想着贪心 &#xff0c;用自己直觉也会有思路。 代码随想录 思路 直觉&#xff0c;直接写&…

7. C++通过select的方式实现高性能网络服务器

什么是异步IO 异步IO指的是用户程序将IO请求提交后,无需等待IO操作的完成,而是可以继续处理别的事情。 所谓异步IO&#xff0c;是指以事件触发的机制来对IO操作进行处理。 与多进程和多线程技术相比&#xff0c;异步I/O技术的最大优势是系统开销小&#xff0c;系统不必创建进程…

R语言数据处理(四)

R语言数据处理&#xff08;四&#xff09; 1. 表格合并 1. 表格合并 &#x1f680;&#x1f680;&#x1f680;代码功能&#xff1a; 从指定文件夹中读取所有 .xlsx 文件&#xff0c;并提取每个文件中特定行和列的数据&#xff0c;然后将这些数据合并到一个最终的数据框中&…

在Nano上部署yolov5

确认镜像版本为JetPack4.4.1(L4T 32.4.4)以上版本 下载链接下载pytorch+nvidia docker镜像(pytorch1.6+torchvision0.7.0)yolov5opencv4.4.0 1. 在已经部署了镜像的机器上获取镜像   1.1 获取镜像名

《Ai学习笔记》-模型集成部署

后续大多数模型提升速度和精度&#xff1a; 提升速度&#xff1a; -知识蒸馏&#xff0c;以distillBert和tinyBert为代表 -神经网络优化技巧。prune来剪裁多余的网络节点&#xff0c;混合精度&#xff08;fp32和fp26混合来降低计算精度从从而实现速度的提升&#xff09; 提…

【教学类-58-04】黑白三角拼图04(2-10宫格,每个宫格随机1张-6张,带空格纸,1页6张黑白,1张6张白卡)

背景需求&#xff1a; 前期制作了黑白三角拼图2*2、3*3、4*4&#xff0c;确定了基本模板&#xff0c;就可以批量制作更多格子数 【教学类-58-01】黑白三角拼图01&#xff08;2*2宫格&#xff09;固定256种随机抽取10张-CSDN博客文章浏览阅读522次&#xff0c;点赞13次&#x…

零基础学Java(全170集)

课程概述 本课程旨在全面深化对 Java 语言的核心技术理解&#xff0c;并提升编程实践能力。课程内容涵盖以下关键领域&#xff1a; 掌握Java核心语法&#xff0c;为后续学习打下扎实的基础。熟练运用Java常用的类库与开发工具&#xff0c;提高开发效率与质量。解决面向对象编…

卡码网笔试 | 118 小y删数字、119 小红的字符串切割、120 小红的数字匹配

118 小y删数字 逐个数字循环除10&#xff0c;并且用一个变量记录非0位数&#xff0c;最后加起来即可。 代码如下&#xff1a; #include <iostream>using namespace std;int main() {int n;cin >> n;int a[n];int sum 0;for (int i 0; i < n; i) cin >&g…