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

React Native 全新架构来了

React Native 0.76 现已在 npm 上以全新架构默认发布!

在 0.76 版本的发布博客中,我们分享了此版本包含的一系列重大更改。在本文中,我们将概述全新架构以及它如何塑造 React Native 的未来。

全新架构全面支持现代 React 功能,包括 Suspense、Transitions、automatic batching 和 useLayoutEffect。全新架构还包括新的原生模块和原生组件系统,使您能够编写类型安全的代码,直接访问原生接口,无需桥接。

此次发布是自 2018 年以来我们从零开始重写 React Native 的成果,我们特别注意使全新架构对于大多数应用来说是一个渐进式迁移过程。2021 年,我们成立了全新架构工作组,与社区合作,确保整个 React 生态系统的升级体验顺利进行。

大多数应用将能够以与其他任何版本相同的努力级别采用 React Native 0.76。最流行的 React Native 库已经支持全新架构。全新架构还包括一个自动互操作层,以实现与针对旧架构的库的向后兼容性。

在过去几年的开发过程中,我们的团队公开分享了对全新架构的愿景。如果您错过了其中的任何讲座,请在以下链接查看:

  • React Native EU 2019 - 新的 React Native
  • React Conf 2021 - React 18 主旨演讲
  • App.js 2022 - 将新的 React Native 架构引入开源社区
  • React Conf 2024 - 第二天主旨演讲

新架构是什么

新架构是对支撑 React Native 的主要系统的全面重写,包括组件的渲染方式、JavaScript 抽象与原生抽象的通信方式以及跨不同线程的工作调度方式。尽管大多数用户无需了解这些系统的具体工作原理,但这些变化带来了性能提升和新的功能。

在旧架构中,React Native 使用异步桥接与原生平台通信。为了渲染一个组件或调用一个原生函数,React Native 需要将原生函数调用序列化并通过桥接队列化,这些调用将被异步处理。这种架构的好处是,主线程不会因渲染更新或处理原生模块函数调用而被阻塞,因为所有工作都在后台线程完成。

然而,用户期望与交互的即时反馈,使应用能够像原生应用一样响应。这意味着某些更新需要在用户输入后同步渲染,可能会中断任何正在进行的渲染。由于旧架构仅支持异步,我们需要重写它以同时支持异步和同步的更新。

此外,在旧架构中,通过桥接序列化函数调用很快成为一个瓶颈,尤其是在频繁更新或处理大型对象时。这使得应用难以稳定地达到 60+ 帧每秒(FPS)。同时也存在同步问题:当 JavaScript 层和原生层不同步时,无法同步地调和它们,导致诸如列表显示空白帧和因中间状态渲染导致的视觉 UI 跳跃等错误。

最后,由于旧架构使用原生层次结构保持单一的 UI 复制,并在原地修改该复制,布局只能在单一线程上计算。这使得处理诸如用户输入等紧急更新变得不可能,且布局无法同步读取,例如在布局效果中读取以更新工具提示的位置。

所有这些问题意味着无法正确支持 React 的并发特性。为了解决这些问题,新架构包括四个主要部分:

  • 新的原生模块系统
  • 新的渲染器
  • 事件循环
  • 移除桥接

新的原生模块系统允许 React Native 渲染器同步访问原生层,这使其能够异步和同步地处理事件、调度更新以及读取布局。新的原生模块默认采用懒加载,显著提升了应用的性能。

新的渲染器能够在多个线程上处理多个进行中的树,这使得 React 能够处理多个并发的更新优先级,无论是在主线程还是后台线程。它还支持同步或异步地从多个线程读取布局,以支持更响应的用户界面而不会出现卡顿。

新的事件循环能够按照明确定义的顺序在 JavaScript 线程上处理任务。这使得 React 能够中断渲染以处理事件,从而使紧急的用户事件能够优先于较低优先级的 UI 过渡。事件循环还与 Web 规范保持一致,因此我们可以支持浏览器特性,如微任务(microtasks)、MutationObserver 和 IntersectionObserver。

最后,移除桥接允许更快的启动速度和 JavaScript 与原生运行时之间的直接通信,从而最小化工作切换的成本。这也使得错误报告和调试更加完善,减少了因未定义行为导致的崩溃。

新架构现已准备好用于生产环境。它已在 Meta 的 Facebook 应用和其他产品中大规模使用。我们在为 Quest 设备开发的 Facebook 和 Instagram 应用中成功使用了 React Native 和新架构。

我们的合作伙伴已经在生产环境中使用新架构数月了:请查看 Expensify 和 Kraken 的成功案例,并尝试 BlueSky 的新版本。

新的原生模块

新的原生模块系统是 JavaScript 与原生平台通信方式的重大重写。它完全使用 C++ 编写,解锁了许多新功能:

  • 与原生运行时的同步访问
  • JavaScript 与原生代码之间的类型安全
  • 跨平台的代码共享
  • 默认的懒加载模块

在新的原生模块系统中,JavaScript 与原生层现在可以通过 JavaScript 接口(JSI)进行同步通信,无需使用异步桥接。这意味着您的自定义原生模块现在可以同步调用一个函数,返回一个值,并将该值传递回另一个原生模块函数。

在旧架构中,为了处理来自原生函数调用的响应,您需要提供一个回调函数,并且返回的值需要是可序列化的:

// ❌ Sync callback from Native Module
nativeModule.getValue(value => {// ❌ value cannot reference a native objectnativeModule.doSomething(value);
});

在新架构中,您可以对原生函数进行同步调用:

// ✅ Sync response from Native Module
const value = nativeModule.getValue();// ✅ value can be a reference to a native object
nativeModule.doSomething(value);

有了新架构,您终于可以利用 C++ 原生实现的全部能力,同时仍然可以通过 JavaScript/TypeScript API 访问它。新的模块系统支持用 C++ 编写的模块,因此您可以编写一次模块,它可以在所有平台上工作,包括 Android、iOS、Windows 和 macOS。用 C++ 实现模块允许更细粒度的内存管理和性能优化。

此外,借助 Codegen,您的模块可以在 JavaScript 层和原生层之间定义强类型的契约。根据我们的经验,跨边界的类型错误是跨平台应用程序崩溃最常见的原因之一。Codegen 让您能够克服这些问题,同时为您生成样板代码。

最后,模块现在是懒加载的:它们只有在实际需要时才加载到内存中,而不是在启动时加载。这减少了应用程序的启动时间,并在应用复杂性增加时保持较低的启动时间。

像 react-native-mmkv 这样的流行库已经从迁移到新的原生模块中受益:

“新的原生模块极大地简化了 react-native-mmkv 的设置、自动链接和初始化。多亏了新架构,react-native-mkv 现在是一个纯 C++ 原生模块,这使它能够在任何平台上工作。新的 Codegen 使 MMKV 完全类型安全,通过强制 null 安全性,修复了长期存在的 NullPointerReference 问题,并且能够同步调用原生模块函数,使我们能够用新的原生模块 API 替换自定义的 JSI 访问。”

新的渲染器

我们还完全重写了原生渲染器,带来了几个好处:

更新可以在不同的线程上以不同的优先级进行渲染。布局可以同步读取,并跨不同的线程进行。渲染器使用 C++ 编写,并在所有平台上共享。

更新后的原生渲染器现在将视图层次结构存储在不可变的树结构中。这意味着 UI 以一种无法直接更改的方式存储,允许线程安全地处理更新。这使得它能够处理多个进行中的树,每个树代表用户界面的不同版本。因此,更新可以在后台渲染而不会阻塞 UI(例如在过渡期间)或主线程(响应用户输入)。

通过支持多线程,React 可以中断低优先级的更新来渲染紧急更新,例如用户输入生成的更新,然后根据需要恢复低优先级的更新。新的渲染器还可以同步地跨不同的线程读取布局信息。这使得低优先级的更新可以在后台计算,并在需要时进行同步读取,例如重新定位工具提示。

最后,用 C++ 重写渲染器使其能够在所有平台上共享。这确保了相同的代码可以在 iOS、Android、Windows、macOS 以及任何其他 React Native 支持的平台上运行,提供一致的渲染能力,而无需为每个平台重新实现。

这是实现我们多平台愿景的重要一步。例如,View Flattening 是一种仅用于 Android 的优化,以避免深层次的布局树。新的渲染器采用共享的 C++ 核心,将这一功能带到了 iOS。这种优化是自动的,不需要设置,随着共享渲染器一起免费提供。

通过这些更改,React Native 现在完全支持并发 React 功能,如 Suspense 和 Transitions,使构建复杂的用户界面变得更加容易,这些界面能够快速响应用户输入而不会出现卡顿、延迟或视觉跳跃。未来,我们将利用这些新功能为内置组件如 FlatList 和 TextInput 带来更多改进。

像 Reanimated 这样流行的库已经开始利用新的渲染器:

“Reanimated 4,目前正在开发中,引入了一个与新的渲染器直接协作的新动画引擎,允许其在不同线程上处理动画和管理布局。新的渲染器的设计真正使这些功能能够在不依赖众多变通方法的情况下构建。此外,由于它是用 C++ 实现并在所有平台上共享,Reanimated 的大部分代码可以一次编写,减少了平台特定的问题,最小化了代码库,并简化了对非树内平台的采用。”

事件循环

新架构使我们能够实现一个明确定义的事件循环处理模型,如本 RFC 中所述。该 RFC 遵循 HTML 标准中描述的规范,并描述了 React Native 如何在 JavaScript 线程上执行任务。

实现一个明确定义的事件循环弥合了 React DOM 和 React Native 之间的差距:React Native 应用程序的行为现在更接近于 React DOM 应用程序的行为,使其更易于一次性学习和在任何地方编写。

事件循环为 React Native 带来了许多好处:

  • 中断渲染以处理事件和任务的能力
  • 与 Web 规范更紧密的对齐
  • 为更多浏览器功能打下基础

借助事件循环,React 能够可预测地排序更新和事件。这允许 React 用紧急的用户事件中断低优先级的更新,而新的渲染器使我们能够独立渲染这些更新。

事件循环还使事件和任务(如定时器)的行为与 Web 规范保持一致,这意味着 React Native 的工作方式更像用户在 Web 中熟悉的方式,并且允许 React DOM 和 React Native 之间更好的代码共享。

它还允许实现更多符合规范的浏览器功能,如微任务(microtasks)、MutationObserver 和 IntersectionObserver。这些功能在 React Native 中尚未准备好使用,但我们正在努力在未来为您提供这些功能。

最后,事件循环和新的渲染器的更改支持同步读取布局,使 React Native 能够为 useLayoutEffect 提供适当的支持,以同步读取布局信息并在同一帧中更新 UI。这使您能够在元素显示给用户之前正确定位它们。

有关更多详细信息,请参阅 useLayoutEffect。

移除桥接

在新架构中,我们还彻底移除了 React Native 对桥接的依赖,改为使用 JSI(JavaScript 接口)进行 JavaScript 和原生代码之间的直接、高效通信:

移除桥接通过避免桥接初始化来提升启动时间。例如,在旧架构中,为了向 JavaScript 提供全局方法,我们需要在启动时在 JavaScript 中初始化一个模块,这会导致应用启动时间略有延迟:

// ❌ Slow initialization
import {NativeTimingModule} from 'NativeTimingModule';
global.setTimeout = timer => {NativeTimingModule.setTimeout(timer);
};// App.js
setTimeout(() => {}, 100);

在新架构中,我们可以直接从 C++ 绑定方法:

// ✅ Initialize directly in C++
runtime.global().setProperty(runtime, "setTimeout", createTimer);// App.js
setTimeout(() => {}, 100);

重写还改善了错误报告,特别是在启动时的 JavaScript 崩溃,并减少了因未定义行为导致的崩溃。如果发生崩溃,新的 React Native 开发工具简化了调试过程并支持新架构。为了向后兼容,桥接仍然保留,以支持逐步迁移到新架构。未来,我们将完全移除桥接代码。

渐进式迁移

我们预计大多数应用可以以与其他版本相同的努力程度升级到 0.76。

当您升级到 0.76 时,新架构和 React 18 将默认启用。然而,为了使用并发特性并充分利用新架构的所有优点,您的应用和库需要逐步迁移以完全支持新架构。

在首次升级时,您的应用将运行在新架构上,并与旧架构通过自动互操作层进行交互。对于大多数应用来说,这无需任何更改即可正常工作,但互操作层存在已知的限制,因为它不支持访问自定义 Shadow Nodes 或并发特性。

要使用并发特性,应用还需要通过遵循 React 规则来更新以支持并发 React。要将您的 JavaScript 代码迁移到 React 18 及其语义,请参阅 React 18 升级指南。

总体策略是让您的应用在不破坏现有代码的情况下运行在新架构上。然后,您可以以自己的节奏逐步迁移应用。对于已将所有模块迁移到新架构的新界面,您可以立即开始使用并发特性。对于现有界面,您可能需要先解决一些问题并迁移模块,然后再添加并发特性。

我们已与最流行的 React Native 库合作,以确保对新架构的支持。超过 850 个库已兼容新架构,包括所有每周下载量超过 20 万次的库(约占下载库的 10%)。您可以在 reactnative.directory 网站上检查库与新架构的兼容性:

有关升级的更多详细信息,请参阅下方的《如何升级》。

新功能

新架构全面支持 React 18、并发特性以及 React Native 中的 useLayoutEffect。有关 React 18 功能的完整列表,请参阅 React 18 博客文章。

过渡(Transitions)

过渡是 React 18 中的一个新概念,用于区分紧急更新和非紧急更新。

紧急更新反映了直接的交互,如输入和点击。过渡更新则是将 UI 从一个视图过渡到另一个视图。

紧急更新需要立即响应,以符合我们对物理对象行为的直觉。然而,过渡更新则不同,因为用户不期望在屏幕上看到每一个中间值。在新架构中,React Native 能够分别支持渲染紧急更新和过渡更新。

通常,为了获得最佳的用户体验,单一的用户输入应导致一个紧急更新和一个非紧急更新。类似于 ReactDOM,诸如点击(press)或更改(change)等事件被视为紧急的并立即渲染。您可以在输入事件中使用 startTransition API 来告知 React 哪些更新是“过渡”,并且可以延迟到后台处理:

import {startTransition} from 'react';// Urgent: Show the slider value
setCount(input);// Mark any state updates inside as transitions
startTransition(() => {// Transition: Show the resultssetNumberOfTiles(input);
});

将紧急事件与过渡分离,可以实现更具响应性的用户界面以及更直观的用户体验。

以下是没有过渡的旧架构(上)与有过渡的新架构(下)的对比:


有关更多信息,请参阅《支持并发渲染器和功能》。

自动批处理

升级到新架构后,您将受益于 React 18 中的自动批处理。自动批处理允许 React 在渲染时将更多的状态更新批量处理,以避免渲染中间状态。这使得 React Native 更加快速,并且不易出现卡顿,而无需开发者编写任何额外代码。


在旧架构(左侧)中,会渲染更多的中间状态,即使滑块停止移动,UI 仍会持续更新。新架构(右侧)由于自动批处理更新,渲染的中间状态更少,渲染完成得更快。

有关更多信息,请参阅《支持并发渲染器和功能》。

useLayoutEffect

基于事件循环和同步读取布局的能力,在新架构中,我们为 React Native 增加了对 useLayoutEffect 的正确支持。

在旧架构中,您需要使用异步的 onLayout 事件来读取视图的布局信息(这也是异步的)。因此,至少会有一帧的布局是错误的,直到布局被读取和更新,这会导致工具提示等元素被放置在错误的位置,例如:

// ❌ async onLayout after commit
const onLayout = React.useCallback(event => {// ❌ async callback to read layoutref.current?.measureInWindow((x, y, width, height) => {setPosition({x, y, width, height});});
}, []);// ...
<ViewWithTooltiponLayout={onLayout}ref={ref}position={position}
/>;

新架构通过允许在 useLayoutEffect 中同步访问布局信息来解决这个问题:

// ✅ sync layout effect during commit
useLayoutEffect(() => {// ✅ sync call to read layoutconst rect = ref.current?.getBoundingClientRect();setPosition(rect);
}, []);// ...
<ViewWithTooltip ref={ref} position={position} />;

这个更改允许您同步读取布局信息,并在同一帧内更新 UI,从而在元素显示给用户之前正确定位它们:


有关更多信息,请参阅《同步布局和效果》文档。

完整支持 Suspense

Suspense 允许您声明性地为组件树的一部分指定加载状态,当该部分尚未准备好显示时,可以显示一个备用内容:

<Suspense fallback={<Spinner />}><Comments />
</Suspense>

我们在几年前引入了有限版本的 Suspense,而 React 18 则增加了对其的完整支持。直到现在,React Native 尚未能够支持 Suspense 的并发渲染。

新架构包括 React 18 中引入的对 Suspense 的全面支持。这意味着您现在可以在 React Native 中使用 Suspense 来处理组件的加载状态,并且被挂起的内容将在后台渲染,而加载状态将被显示,从而为可见内容的用户输入赋予更高的优先级。

更多信息,请参阅 React 18 中的 Suspense RFC。

如何升级

要升级到 0.76,请按照发布公告中的步骤进行。由于此版本也升级到了 React 18,您还需要遵循 React 18 升级指南。

这些步骤对于大多数应用来说已经足够,感谢新架构与旧架构之间的互操作层,可以顺利升级到新架构。然而,为了充分利用新架构并开始使用并发特性,您需要迁移自定义的原生模块和原生组件,以支持新的原生模块和原生组件 API。

如果不迁移自定义的原生模块,您将无法享受到共享 C++、同步方法调用或来自 Codegen 的类型安全的优势。如果不迁移原生组件,您将无法使用并发特性。我们建议尽快将所有原生组件和原生模块迁移到新架构。

应用程序

如果您是应用开发者,为了完全支持新架构,您需要升级您的库、自定义原生组件和自定义原生模块,以全面支持新架构。

我们已经与最流行的 React Native 库合作,确保对新架构的支持。您可以在 reactnative.directory 网站上检查库与新架构的兼容性。

如果您的应用依赖的任何库尚未兼容,您可以:

  • 在该库的仓库中提交一个 issue,要求作者迁移到新架构。
  • 如果该库不再维护,考虑使用具有相同功能的替代库。
  • 在这些库迁移期间,选择不使用新架构。

如果您的应用有自定义的原生模块或自定义的原生组件,感谢我们的互操作层,我们预计它们可以正常工作。然而,我们建议将它们升级到新的原生模块和原生组件 API,以全面支持新架构并采用并发特性。

请按照以下指南将您的模块和组件迁移到新架构:

  • 原生模块
  • 原生组件

如果您是库的维护者,请首先测试您的库是否与互操作层兼容。如果不兼容,请在新架构工作组中提交一个 issue。

为了全面支持新架构,我们建议尽快将您的库迁移到新的原生模块(Native Module)和原生组件(Native Component)API。这将使您的库的用户能够充分利用新架构并支持并发特性。

您可以参考以下指南,将您的模块和组件迁移到新架构:

原生模块原生组件

选择退出

如果由于任何原因,新架构在您的应用中表现不正常,您始终可以选择退出,直到您准备好再次启用它。

要选择退出新架构:

在 Android 上,修改 android/gradle.properties 文件,并关闭 newArchEnabled 标志:

-newArchEnabled=true
+newArchEnabled=false

在 iOS 上,您可以通过运行以下命令重新安装依赖

RCT_NEW_ARCH_ENABLED=0 bundle exec pod install
感谢

将新架构交付给开源社区是一项巨大的努力,经过我们多年的研究和开发。我们想花一点时间感谢所有现任和曾经的 React 团队成员,他们帮助我们实现了这一成果。

我们也非常感谢所有与我们合作的合作伙伴使这一切成为可能。具体来说,我们要特别感谢:

  • Expo,感谢其早期采用新架构,并支持迁移最流行库的工作。
  • Software Mansion,感谢其维护生态系统中的关键库,早期将其迁移到新架构,并在调查和修复各种问题上提供的帮助。
  • Callstack,感谢其维护生态系统中的关键库,早期将其迁移到新架构,并支持社区 CLI 的工作。
  • 微软,感谢其为 react-native-windows 和 react-native-macos 以及其他多个开发工具添加新架构的实现。
  • Expensify、Kraken、BlueSky 和 Brigad,感谢它们在采用新架构方面的先锋作用,并报告各种问题,使我们能够为其他人修复这些问题。
  • 所有独立的库维护者和开发者,感谢他们通过测试新架构、修复一些问题并就不明确的事项提出问题,为我们澄清问题作出的贡献。

相关文章:

React Native 全新架构来了

React Native 0.76 现已在 npm 上以全新架构默认发布&#xff01; 在 0.76 版本的发布博客中&#xff0c;我们分享了此版本包含的一系列重大更改。在本文中&#xff0c;我们将概述全新架构以及它如何塑造 React Native 的未来。 全新架构全面支持现代 React 功能&#xff0c;…...

@ConditionalOnClass编译问题

@ConditionalOnClass/@ConditionalOnMissingClass 使用场景 和@Configuration一起使用,用于条件注入 问题一 为什么我们使用的第三方jar中,指定的类型不存在,第三方jar在编译时仍然通过?还打出了jar包? 下图为spring-boot-autoconfigure中的一个配置类SecurityDataCo…...

Redis - 哨兵(Sentinel)

Redis 的主从复制模式下&#xff0c;⼀旦主节点由于故障不能提供服务&#xff0c;需要⼈⼯进⾏主从切换&#xff0c;同时⼤量 的客⼾端需要被通知切换到新的主节点上&#xff0c;对于上了⼀定规模的应⽤来说&#xff0c;这种⽅案是⽆法接受的&#xff0c; 于是Redis从2.8开始提…...

unity显示获取 年月日周几【日期】

unity显示获取 年月日周几【日期】 public void ShowDate(Text txt){//txt.text DateTime now DateTime.Now; // 获取当前时间int year now.Year; // 获取年份int month now.Month; // 获取月份&#xff08;1-12&#xff09;int day now.Day; // 获取天数&#xff08;1-31&…...

MYSQL隔离性原理——MVCC

表的隐藏字段 表的列包含用户自定义的列和由系统自动创建的隐藏字段。我们介绍3个隐藏字段&#xff0c;不理解也没有关系&#xff0c;理解后面的undo log就懂了&#xff1a; DB_TRX_ID &#xff1a;6 byte&#xff0c;最近修改( 修改/插入 )事务ID&#xff0c;记录创建这条记…...

Android ANR分析总结

1、ANR介绍 ANR&#xff08;Application Not Responding&#xff09;指的是应用程序无响应&#xff0c;当Android应用程序在主线程上执行长时间运行的操作或阻塞I/O操作时发生。这可能导致应用程序界面冻结或无法响应用户输入。 1、Service ANR&#xff1a;前台20s&#xff0…...

Three.js 纹理贴图

1. 纹理贴图 在Three.js中&#xff0c;纹理贴图是一种将二维图像贴到三维物体表面的技术&#xff0c;以增强物体的视觉表现。纹理贴图可以使物体表面更加真实、细腻&#xff0c;为场景增色不少。 在Three.js中&#xff0c;纹理贴图的加载主要通过THREE.TextureLoader类实现。…...

2024年软件设计师中级(软考中级)详细笔记【12】软件系统分析与设计

目录 前言第12章 软件系统分析与设计12.2 数据库分析与设计12.2.1 数据库设计的策略与步骤12.2.2 需求分析12.2.3 概念结构设计12.2.4 逻辑结构设计12.2.5 数据库的物理设计 结语 前言 在备考软件设计师中级考试的过程中&#xff0c;我遇到了些许挑战&#xff0c;也收获了宝贵…...

【Windows】CMD命令学习——系统命令

CMD&#xff08;命令提示符&#xff09;是Windows操作系统中的一个命令行解释器&#xff0c;允许用户通过输入命令来执行各种系统操作。 系统命令 systeminfo - 显示计算机的详细配置信息。 tasklist - 显示当前正在运行的进程列表。 taskkill - 终止正在运行的进程。例如&am…...

React第一个项目

运行效果&#xff1a; 知识讲解&#xff1a; 组件&#xff1a;先定义后使用&#xff0c;用户界面的构成要素&#xff08;标签、css和JavaScript&#xff09; 定义组件&#xff1a; 导出组件&#xff1a;export default 前缀是JavaScript标准语法 定义函数&#xff1a;function …...

计算机网络基本概念总结

IP地址 概念 使网络中的设备都有唯一的地址标识&#xff0c;用于表示其在网络中的位置。 格式 IP地址是一个32位的二进制数&#xff0c;通常被分割为4个8位二进制数&#xff08;也就是4个字节&#xff09;&#xff0c;如&#xff1a;01100100.00001000.00001010.00000110。通常…...

考研要求掌握C语言(归并排序)

归并排序考啥&#xff1f; 在考研中归并排序只出在选择题&#xff0c;理解原理很重要 且在考研中考两两归并&#xff0c;还是比较简单的 归并排序原理 就是每次分一半&#xff0c;直到每一半只含有一个或不能再分时&#xff0c;一半一半的进行排序&#xff0c;最终合并两个…...

Spring Authorization Server:实现OAuth2认证服务

Spring Authorization Server为构建安全的SpringBoot应用提供了一系列解决方案,本节课程我们将结合OAuth2来实现认证服务,该认证服务将支持常用的OAuth2授权模式和刷新Token。 Spring Authorization Server简介 Spring Authorization Server是一个安全框架,它提供了OAuth 2.…...

Rocky、Almalinux、CentOS、Ubuntu和Debian系统初始化脚本v9版

Rocky、Almalinux、CentOS、Ubuntu和Debian系统初始化脚本 Shell脚本源码地址&#xff1a; Gitee&#xff1a;https://gitee.com/raymond9/shell Github&#xff1a;https://github.com/raymond999999/shell脚本可以去上面的Gitee或Github代码仓库拉取。 支持的功能和系统&am…...

ScrumMaster认证机构及CSM、PSM、RSM价值解析

近十年Scrum在国内备受关注&#xff0c;成为一种最流行的现代敏捷工作方式。ScrumMaster这一独特的角色&#xff0c;在企业内部推动Scrum落地的过程中越来越重要。各种ScrumMaster认证课程也蜂拥而至&#xff0c;甚至鱼目混珠。 我们为大家梳理了目前市面上出现的ScrumMaster认…...

借助 Pause 容器调试 Pod

借助 Pause 容器调试 Pod 在 K8S 中&#xff0c;Pod 是最核心、最基础的资源对象&#xff0c;也是 Kubernetes 中调度最小单元。在介绍 Pause 容器之前需要先说明下 Pod 与容器的关系来理解为什么需要 Pause 容器来帮助调试 1. Pod 与 容器的关系 Pod 是一个抽象的逻辑概念&…...

PostgreSQL 开启密码验证插件

我们知道在数据安全和等保要求中&#xff0c;用户的密码复杂度需要满足一定的条件&#xff0c;那么在 PostgreSQL 数据库中如何保证创建的用户的密码满足这些要求呢。 [rootlocalhost ~]# su - postgres [postgreslocalhost ~]$ cd /usr/local/pgsql-12.8/data/ [postgresloca…...

Go 语言已立足主流,编程语言排行榜24 年 11 月

Go语言概述 Go语言&#xff0c;简称Golang&#xff0c;是由Google的Robert Griesemer、Rob Pike和Ken Thompson在2007年设计&#xff0c;并于2009年11月正式宣布推出的静态类型、编译型开源编程语言。Go语言以其提高编程效率、软件构建速度和运行时性能的设计目标&#xff0c;…...

flutter下拉刷新上拉加载的简单实现方式三

使用 CustomScrollView 结合 SliverList 实现了一个支持下拉刷新和上拉加载更多功能的滚动列表&#xff0c;对下面代码进行解析学习。 import dart:math;import package:flutter/material.dart;import custom_pull/gsy_refresh_sliver.dart; import package:flutter/cupertino…...

【C++ 20进阶(2):属性 Attribute】

【C 20进阶&#xff08;2&#xff09;&#xff1a;属性 Attribute】 原文&#xff1a;https://blog.csdn.net/weixin_44259356/article/details/143663492 引言 本篇文章为系列文章将着重介绍C20新特性&#xff0c;一是希望可以和大家交流分享&#xff0c;二是也便于自己巩固…...

Linux之守护进程

在Linux系统中&#xff0c;进程一般分为前台进程、后台进程和守护进程3类。 一 守护进程 定义: 1.守护进程是在操作系统后台运行的一种特殊类型的进程&#xff0c;它独立于前台用户界面&#xff0c;不与任何终端设备直接关联。这些进程通常在系统启动时启动&#xff0c;并持…...

Java集合操作常见错误与最佳实践

错误69:搜索无关类型的对象 泛型方法的类型安全漏洞 在Java引入参数化类型前,集合元素只能声明为Object类型,导致可以随意将字符串添加到数值列表中。虽然泛型机制对添加元素的方法进行了类型约束,但搜索和删除相关方法仍保留了Object类型的参数设计。这包括以下关键方法…...

算力卡上部署OCR文本识别服务与测试

使用modelscope上的图像文本行检测和文本识别模型进行本地部署并转为API服务。 本地部署时把代码中的检测和识别模型路径改为本地模型的路径。 关于模型和代码原理可以参见modelscope上这两个模型相关的页面&#xff1a; iic/cv_resnet18_ocr-detection-db-line-level_damo iic…...

【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter3 项目实践 - 3人脸识别采集统计人脸检测语音识别

https://www.bilibili.com/video/BV1WgQdYNERe/?p87&spm_id_from333.788.top_right_bar_window_history.content.click&vd_sourcec919d6976fd77ac77f9860cf2e7e0e11 1 人脸识别 # 1 采集完-人脸图片好上传到百度人脸识别-后期使用百度进行人脸识别-保存、删除等-后期…...

threejs渲染器和前端UI界面

1. three.js Canvas画布布局 学习本节课之前&#xff0c;可以先回顾下第一章节入门部分的6和12两小节关于threejs Canvas画布布局的讲解。 网页上局部特定尺寸&#xff1a;1.6 第一个3D案例—渲染器(opens new window) 全屏&#xff0c;随窗口变化:1.12 Canvas画布布局和全屏…...

Lua 的速度为什么比 Python 快

Lua 的执行速度通常比 Python 快&#xff0c;主要原因在于其解释器设计轻量、虚拟机效率高、内存管理策略更为精简&#xff0c;以及语言本身对动态特性的控制较严。其中&#xff0c;Lua 使用了 register-based 的虚拟机架构&#xff0c;而 Python&#xff08;CPython&#xff0…...

Fine Pruned Tiled Light Lists(精细删减的分块光照列表)

概括 在这篇文章&#xff0c; 我将介绍一种Tiled Light 变体&#xff0c;主要针对AMD Graphics Core Next&#xff08;GCN&#xff09;架构进行优化&#xff0c;我们的方法应用于游戏 古墓丽影:崛起 中&#xff0c;特别是我们在通过光列表生成和阴影贴图渲染之间交错进行异步计…...

Unity中的AudioManager

1.先贴代码 using UnityEngine; using System.Collections.Generic; using System.Collections; using UnityEngine.SceneManagement;public class AudioManager : MonoSingleton<AudioManager> {[Header("Audio Settings")][SerializeField] private int ini…...

C++ 观察者模式:设计与实现详解

一、引言 在现代软件开发中,组件间的交互与通信是系统设计的核心挑战之一。观察者模式(Observer Pattern)作为一种行为设计模式,提供了一种优雅的解决方案,用于实现对象间的一对多依赖关系。本文将深入探讨 C++ 中观察者模式的设计理念、实现方式及其应用场景。 二、观察…...

E. Melody 【CF1026 (Div. 2)】 (求欧拉路径之Hierholzer算法)

E. Melody 思路 将所有出现过的音量和音高看作一个点&#xff0c;一个声音看作一条边&#xff0c;连接起来。那么很容易知道要找的就是图上的一条欧拉路径&#xff08;类似一笔画问题&#xff09; 又已知存在欧拉路径的充要条件为&#xff1a;度数为奇数的点的个数为0或者2个…...