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

HarmonyOS:状态管理最佳实践

一、概述

在声明式UI编程范式中,UI是应用程序状态的函数,应用程序状态的修改会更新相应的UI界面。ArkUI采用了MVVM模式,其中ViewModel将数据与视图绑定在一起,更新数据的时候直接更新视图。如下图所示:

ArkUI的MVVM模式图解

在这里插入图片描述

ArkUI提供了一系列装饰器实现ViewModel的能力,如@Prop、@Link、@Provide、LocalStorage等。当自定义组件内变量被装饰器装饰时变为状态变量,状态变量的改变会引起UI的渲染刷新。

在ArkUI的开发过程中,如果没有选择合适的装饰器或合理的控制状态更新范围,可能会导致以下问题:

  1. 状态和UI的不一致,如同一状态的界面元素展示的UI不同,或UI界面展示的不是最新的状态。
  2. 非必要的UI视图刷新,如只修改局部组件状态时导致组件所在页面的整体刷新。

当用户与界面产生交互行为时,状态的修改是通过事件驱动处理的。事件的处理可以在应用的任何地方,如果没有进行适当的逻辑处理管理也会导致代码冗余和不利于维护。

本文旨在从装饰器的选择、使用以及状态的逻辑处理管理方面解决以上问题,以实现更好的状态管理。

二、合理选择装饰器

2.1 避免不必要的状态变量的使用

删除冗余的状态变量标记
状态变量的管理有一定的开销,应在合理场景使用,普通的变量用状态变量标记可能会导致性能劣化。

反例1

@Observed
class Translate {translateX: number = 20;
}
@Entry
@Component
struct MyComponent {@State translateObj: Translate = new Translate(); // 变量translateObj没有关联任何UI组件,不应该定义为状态变量@State buttonMsg: string = 'I am button'; // 变量buttonMsg没有关联任何UI组件,不应该定义为状态变量build() {}
}

以上示例中变量translateObj,buttonMsg没有关联任何UI组件,没有关联任何UI组件的状态变量不应该定义为状态变量,否则读写状态变量都会影响性能。

反例2

@Observed
class Translate {translateX: number = 20;
}
@Entry
@Component
struct MyComponent {@State translateObj: Translate = new Translate();@State buttonMsg: string = 'I am button';build() {Column() {Button(this.buttonMsg) // 这里只是读取变量buttonMsg的值,没有任何写的操作}}
}

以上示例中变量buttonMsg仅有读取操作,没有修改过,没有修改过的状态变量不应该定义为状态变量,否则读状态变量会影响性能。

正例

@Observed
class Translate7 {translateX: number = 20;
}@Entry
@Component
struct UnnecessaryState1 {@State translateObj: Translate = new Translate7(); // 同时存在读写操作,并关联了Button组件,推荐使用状态变量buttonMsg = 'I am button'; // 仅读取变量buttonMsg的值,没有任何写的操作,直接使用一般变量即可build() {Column() {Button(this.buttonMsg).onClick(() => {animateTo({duration: 50}, () => {this.translateObj.translateX = (this.translateObj.translateX + 50) % 150; // 点击时给变量translateObj重新赋值})console.log(`执行了水平偏移位置动画, this.translateObj.translateX = ${this.translateObj.translateX}`)})}.translate({x: this.translateObj.translateX // 读取translateObj中的值})}
}

效果图

在这里插入图片描述

没有关联任何UI组件的状态变量和没有修改过的状态变量不应该定义为状态变量,直接使用一般变量即可,否则会影响性能。

建议使用临时变量替换状态变量

状态变量发生变化时,ArkUI会查询依赖该状态变量的组件并执行依赖该状态变量的组件的更新方法,完成组件渲染的行为。通过使用临时变量的计算代替直接操作状态变量,可以使ArkUI仅在最后一次状态变量变更时查询并渲染组件,减少不必要的行为,从而提高应用性能。状态变量行为可参考@State装饰器:组件内状态。

反例

@Entry
@Component
struct Index {@State message: string = '';appendMsg(newMsg: string) {this.message += newMsg;this.message += ';';this.message += '<br/>';}build() {Column() {Button('点击打印日志').onClick(() => {this.appendMsg('操作状态变量');}).width('90%').backgroundColor(Color.Blue).fontColor(Color.White).margin({ top: 10})}.justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Center).margin({  top: 15 })}
}

正例

@Entry
@Component
struct UnnecessaryState2 {@State message: string = '';appendMsg(newMsg: string) {let message = this.message;message += newMsg;message += ';';message += '<br/>';this.message = message;}build() {Column() {Button('点击打印日志').onClick(() => {this.appendMsg('操作临时变量');console.log("this.message:", this.message)}).width('90%').backgroundColor(Color.Blue).fontColor(Color.White).margin({ top: 10 })}.justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Center).margin({ top: 15 })}
}

使用临时变量替换状态变量效果图

在这里插入图片描述

三、最小化状态共享范围

在没有强烈的业务需求下,尽可能按照状态需要共享的最小范围选择合适的装饰器。应用开发过程中,按照组件颗粒度,状态一般分为组件内独享的状态和组件间需要共享的状态。

3.1 组件内独享的状态

组件内独享的状态的生命周期和组件同步,状态的定义和更新都在组件内,组件销毁,状态也随即消失。常见于界面UI元素数据,比如当前按钮是否可用、文字是否高亮等。组件内独享的状态使用@State装饰器,被@State装饰器修饰后状态的修改只会触发当前组件实例的重新渲染。如下图主题列表上单个主题组件内使用@State修饰主题是否被选中的变量,当在界面点击主题时在组件内直接修改状态值。此时,只有当前主题的组件实例会重新渲染,其他主题组件不会重新渲染。

HMOS世界App主题选择交互图

在这里插入图片描述

3.2 组件间需要共享的状态

组件间需要共享的状态,按照共享范围从小到大依次有三种场景:父子组件间共享状态,不同子树上组件间共享状态和不同组件树间共享状态。

父子组件间共享状态:如下图,”父组件”和其子组件”子组件A”、”子组件B”共享状态loading。

父子组件间共享状态场景

在这里插入图片描述

不同子树上组件间共享状态:如下图,祖先组件的左子树上”孙子组件AAA”和右子树上”孙子组件BAA”共享状态loading。

不同子树上组件间状态共享场景

在这里插入图片描述

不同组件树间共享状态:如下图,组件树A内”子组件AA”和组件树B内”孙子组件AAA”共享状态loading。

不同组件树间共享状态的场景

在这里插入图片描述

对于上述三种场景,ArkUI提供了@State+@Prop、@State+@Link、@State+@Observed+@ObjectLink、@Provide+@Consume、AppStorage、LocalStorage六种装饰器组合以解决不同范围内的组件间状态共享。按照共享范围能力从小到大,各装饰器组合的共享范围能力和生命周期如下:

  1. @State+@Prop、@State+@Link、@State+@Observed+@ObjectLink:三者的共享范围为从@State所在的组件开始,到@Prop/@Link/@ObjectLink所在组件的整条路径,路径上所有的中间组件通过@Prop/@Link/@ObjectLink都可以共享同一个状态。@State修饰的状态和其所属的自定义组件共享生命周期,在组件内定义时创建,组件销毁时被回收。@Link装饰的变量和其所属的自定义组件共享生命周期。@ObjectLink装饰的变量和其所属的自定义组件共享生命周期。
  2. @Provide+@Consume:状态共享范围是以@Provide所在组件为祖先节点的整棵子树,子树上的任意后代组件通过@Consume都可以共享同一个状态。@Provide修饰的变量与其所属的组件绑定,在组件内定义时被创建,在组件销毁时被回收。
  3. LocalStorage:共享范围为UIAbility内以页面为单位的不同组件树间的共享。存储在LocalStorage中的状态的生命周期与LocalStorage绑定。LocalStorage的生命周期由应用程序决定,当应用释放最后一个指向LocalStorage的引用时,LocalStorage被垃圾回收。
  4. AppStorage:共享范围是应用全局。AppStorage与应用的进程绑定,由UI框架在应用程序启动时创建,当应用进程终止,AppStorage被回收。

按照软件开发原则,应优先选择共享范围能力小的装饰器方案,减少不同模块间的数据耦合,便于状态及时回收。建议选择装饰器的优先级为:@State+@Prop、@State+@Link、@State+@Observed+@ObjectLink > @Provide+@Consume > LocalStorage > AppStorage。

四、使用监听和订阅精准控制组件刷新

多个组件依赖对象中的不同属性时,直接关联该对象会出现改变任一属性所有组件都刷新的现象,可以通过将类中的属性拆分组合成新类的方式精准控制组件刷新。

在多个组件依赖同一个数据源并根据数据源变化刷新组件的情况下,直接关联数据源会导致每次数据源改变都刷新所有组件。为精准控制组件刷新,可以采取以下策略。

4.1 使用 @Watch 装饰器监听数据源

在组件中使用@Watch装饰器监听数据源,当数据变化时执行业务逻辑,确保只有满足条件的组件进行刷新。

反例

在下面的示例代码中,多个组件直接关联同一个数据源,但是未使用@Watch装饰器和Emitter事件驱动更新,导致了冗余的组件刷新。

@Entry
@Component
struct NoUseWatchListener {@State currentIndex: number = 0; // 当前选中的列表项下标private listData: string[] = [];aboutToAppear(): void {for (let i = 0; i < 10; i++) {this.listData.push(`组件 ${i}`);}}build() {Row() {Column() {List() {ForEach(this.listData, (item: string, index: number) => {ListItem() {ListItemComponent({ item: item, index: index, currentIndex: this.currentIndex })}})}.alignListItem(ListItemAlign.Center)}.width('100%')}.height('100%')}
}@Component
struct ListItemComponent {@Prop item: string;@Prop index: number; // 列表项的下标@Link currentIndex: number;private sizeFont: number = 50;isRender(): number {console.info(`ListItemComponent ${this.index} Text is rendered`);return this.sizeFont;}build() {Column() {Text(this.item).fontSize(this.isRender())// 根据当前列表项下标index与currentIndex的差值来动态设置文本的颜色.fontColor(Math.abs(this.index - this.currentIndex) <= 1 ? Color.Red : Color.Blue).onClick(() => {this.currentIndex = this.index;})}}
}

上述示例中,每个ListItemComponent组件点击Text后会将当前点击的列表项下标index赋值给currentIndex,@Link装饰的状态变量currentIndex变化后,父组件Index和所有ListItemComponent组件中的Index值都会同步发生改变。然后,在所有ListItemComponent组件中,根据列表项下标index与currentIndex的差值的绝对值是否小于等于1来决定Text的颜色,如果满足条件,则文本显示为红色,否则显示为蓝色,下面是运行效果图。

在这里插入图片描述

可以看到每次点击后即使其中部分Text组件的颜色并没有发生改变,所有的Text组件也都会刷新。这是由于ListItemComponent组件中的Text组件直接关联了currentIndex,而不是根据currentIndex计算得到的颜色。

针对上述父子组件层级关系的场景,推荐使用状态装饰器@Watch监听数据源。当数据源改变时,在@Watch的监听回调中执行业务逻辑。组件关联回调的处理结果,而不是直接关联数据源。

正例

下面是对上述示例的优化,展示如何通过@Watch装饰器实现精准刷新。

@Entry
@Component
struct UseWatchListener {@State currentIndex: number = 0; // 当前选中的列表项下标private listData: string[] = [];aboutToAppear(): void {for (let i = 0; i < 10; i++) {this.listData.push(`组件 ${i}`);}}build() {Row() {Column() {List() {ForEach(this.listData, (item: string, index: number) => {ListItem() {ListItemComponent({ item: item, index: index, currentIndex: this.currentIndex })}})}.height('100%').width('100%').alignListItem(ListItemAlign.Center)}.width('100%')}.height('100%')}
}@Component
struct ListItemComponent {@Prop item: string;@Prop index: number; // 列表项的下标@Link @Watch('onCurrentIndexUpdate') currentIndex: number;@State color: Color = Math.abs(this.index - this.currentIndex) <= 1 ? Color.Red : Color.Blue;isRender(): number {console.info(`ListItemComponent ${this.index} Text is rendered`);return 50;}onCurrentIndexUpdate() {// 根据当前列表项下标index与currentIndex的差值来动态修改color的值this.color = Math.abs(this.index - this.currentIndex) <= 1 ? Color.Red : Color.Blue;}build() {Column() {Text(this.item).fontSize(this.isRender()).fontColor(this.color).onClick(() => {this.currentIndex = this.index;})}}
}

上述代码中,ListItemComponent组件中的状态变量currentIndex使用@Watch装饰,Text组件直接关联新的状态变量color。当currentIndex发生变化时,会触发onCurrentIndexUpdate方法,在其中将表达式的运算结果赋值给状态变量color。只有color的值发生变化时,Text组件才会重新渲染,运行效果图如下:

在这里插入图片描述

被依赖的数据源仅在父子或兄弟关系的组件中传递时,可以参考上述示例,使用@State/@Link/@Watch装饰器进行状态管理,实现组件的精准刷新。

当组件关系层级较多但都归属于同一个确定的组件树时,推荐使用@Provide/@Consume传递数据,使用@Watch装饰器监听数据变化,在监听回调中执行业务逻辑。

4.2 使用自定义事件发布订阅

当组件关系复杂或跨越层级过多时,推荐使用EventHub或者Emitter自定义事件发布订阅的方式。当数据源改变时发布事件,依赖该数据源的组件通过订阅事件来获取数据源的改变,完成业务逻辑的处理,从而实现组件的精准刷新。

下面通过部分示例代码介绍使用方式,ButtonComponent组件作为交互组件触发数据变更,ListItemComponent组件接收数据做相应的UI刷新。

UseEmitterPublish.ets代码

import { ButtonComponent22 } from '../components/ButtonComponent';
import { ListItemComponent22 } from '../components/ListItemComponent';@Entry
@Component
struct UseEmitterPublish {listData: string[] = ['A', 'B', 'C', 'D', 'E', 'F'];build() {Column() {Row() {Column() {ButtonComponent22()}}Column() {Column() {List() {ForEach(this.listData, (item: string, index: number) => {ListItemComponent22({ myItem: item, index: index })})}.height('100%').width('100%').alignListItem(ListItemAlign.Center)}}}}
}

由于ButtonComponent组件和ListItemComponent组件的组件关系较为复杂,因此在ButtonComponent组件中的Button回调中,可以使用emitter.emit发送事件,在ListItemComponent组件中订阅事件。在事件触发的回调中接收数据value,通过业务逻辑决定是否修改状态变量color,从而实现精准控制ListItemComponent组件中Text的刷新。

ButtonComponent22.ets代码

@Component
export struct ButtonComponent22 {value: number = 2;build() {Button(`下标是${this.value}的倍数的组件文字变为红色`).onClick(() => {let event: emitter.InnerEvent = {eventId: 1,priority: emitter.EventPriority.LOW};let eventData: emitter.EventData = {data: {value: this.value}};// 发送eventId为1的事件,事件内容为eventDataemitter.emit(event, eventData);this.value++;console.log(`执行了 下标是${this.value}的倍数的组件文字变为红色`)})}
}

ListItemComponent22.ets代码

@Component
export struct ListItemComponent22 {@State color: Color = Color.Black;@Prop index: number;@Prop myItem: string;aboutToAppear(): void {let event: emitter.InnerEvent = {eventId: 1};// 收到eventId为1的事件后执行该回调let callback = (eventData: emitter.EventData): void => {if (eventData.data?.value !== 0 && this.index % eventData.data?.value === 0) {this.color = Color.Red;console.log(`收到eventId为1的事件后执行该回调 ${this.index} 组件文字变为红色`)}};// 订阅eventId为1的事件emitter.on(event, callback);}build() {Column() {Text(this.myItem).fontSize(50).fontColor(this.color)}}
}

效果图

在这里插入图片描述

五、总结

状态管理是MVVM模式中十分复杂的问题,为解决其中状态和视图一致性、渲染性能体验、代码可复用性和可维护性四个问题,本文主要有以下建议点:

  • 在选择装饰器时,应理解各个装饰器的特性和共享范围,结合实际开发场景的优先级,合理选择装饰器,以确保状态和视图的一致性。
  • 在使用装饰器时,对装饰器修饰的复杂变量应进行合理拆分设计,以此减少非必要的组件渲染次数,获得更好的性能体验。
  • 在代码开发过程中,对相似的逻辑处理,应考虑其复用性合理集中处理,以此有效提升代码的可维护性和可复用性。

相关文章:

HarmonyOS:状态管理最佳实践

一、概述 在声明式UI编程范式中&#xff0c;UI是应用程序状态的函数&#xff0c;应用程序状态的修改会更新相应的UI界面。ArkUI采用了MVVM模式&#xff0c;其中ViewModel将数据与视图绑定在一起&#xff0c;更新数据的时候直接更新视图。如下图所示&#xff1a; ArkUI的MVVM模式…...

当AI风暴来袭:中美科技商业版图的迥异走向

当AI风暴来袭:中美科技商业版图的迥异走向 美国科技巨头的 AI 豪赌:Stargate 公司的诞生 2025 年,科技界被一则重磅消息所震动:软银、NVIDIA、Oracle 与 OpenAI 共同组建了 Stargate 公司。这一合作堪称豪华阵容,软银作为全球知名的投资巨头,拥有雄厚的资金实力和广泛的…...

马尔科夫模型和隐马尔科夫模型区别

我用一个天气预报和海藻湿度观测的比喻来解释&#xff0c;保证你秒懂&#xff01; 1. 马尔可夫模型&#xff08;Markov Model, MM&#xff09; 特点&#xff1a;状态直接可见 场景&#xff1a;天气预报&#xff08;晴天→雨天→阴天…&#xff09;核心假设&#xff1a; 下一个…...

面向对象设计原则 - SOLID原则 (基于C++)

SOLID 是面向对象编程中的一组五个设计原则&#xff0c;这些原则旨在帮助开发者创建更灵活、可维护和可扩展的软件系统。它们最初由 Robert C. Martin 提出&#xff0c;并在 2000 年左右被广泛接受。每个字母代表一个不同的原则&#xff1a; 单一职责原则 (Single Responsibil…...

ChatGPT 搜索测试整合记忆功能

据 TestingCatalog 报道&#xff0c;OpenAI 正在测试 ChatGPT 搜索的整合记忆功能&#xff0c;被命名为 “Memory in search”2。以下是关于该功能的具体情况123&#xff1a; 功能特点 个性化搜索&#xff1a;启用该功能后&#xff0c;ChatGPT 能利用存储的记忆数据&#xff0…...

PWM频率测量方法

测量PWM&#xff08;脉宽调制&#xff09;信号的频率是嵌入式系统中的常见需求&#xff0c;尤其是在电机控制、LED调光、传感器信号处理等场景中。 在这里介绍两种测量PWM频率的方法&#xff1a;测频法与测周法。 1、测频&#xff08;率&#xff09;法 原理&#xff1a;在闸门…...

【B站保姆级视频教程:Jetson配置YOLOv11环境(一)镜像下载与烧录】

b站同步视频教程&#xff1a;https://www.bilibili.com/video/BV11r6oYkEFb/ 一、引言 在人工智能与计算机视觉快速发展的当下&#xff0c;Jetson系列开发板凭借强大的性能&#xff0c;成为众多开发者进行深度学习项目的热门选择。YOLOv11作为目标检测领域的先进算法&#xf…...

使用QSqlQueryModel创建交替背景色的表格模型

class UserModel(QSqlQueryModel):def __init__(self):super().__init__()self._query "SELECT name, age FROM users"self.refresh()def refresh(self):self.setQuery(self._query)# 重新定义data()方法def data(self, index, role): if role Qt.BackgroundRole…...

计算机网络__基础知识问答

Question: 1&#xff09;在计算机网络的5层结构中&#xff0c;每一层的功能大概是什么&#xff1f; 2&#xff09;交换机的功能&#xff1f;https://www.bilibili.com/video/BV1na4y1L7Ev 3&#xff09;路由器的功能&#xff1f;https://www.bilibili.com/video/BV1hv411k7n…...

C语言数组详解:从基础到进阶的全面解析

在C语言中&#xff0c;数组是一种基本的数据结构&#xff0c;用于存储多个相同类型的数据。数组的引入使得C语言能够高效地存储和操作大量数据。在任何一个C语言程序中&#xff0c;数组都发挥着极其重要的作用。无论是在算法实现、数据存储、还是在复杂程序的设计中&#xff0c…...

微前端架构在前端开发中的实践与挑战

随着单页面应用&#xff08;SPA&#xff09;和前端框架如 React、Vue、Angular 的快速发展&#xff0c;现代前端应用的复杂度日益提升。尤其是当应用规模逐渐增大时&#xff0c;单一的代码库往往难以应对不同团队的协作和版本管理问题。为了应对这一挑战&#xff0c;微前端架构…...

国内flutter环境部署(记录篇)

设置系统环境变量 export PUB_HOSTED_URLhttps://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn使用以下命令下载flutter镜像 git clone -b stable https://mirror.ghproxy.com/https://github.com/<github仓库地址>#例如flutter仓…...

Julia DataFrames.jl:深入理解和使用

随着数据科学和机器学习的发展&#xff0c;数据框架广泛应用于数据处理与分析工作中。在 Julia 语言中&#xff0c;DataFrames.jl 是一个强大且灵活的数据框库&#xff0c;为数据操作提供了丰富的功能。本文旨在系统地介绍 DataFrames.jl 的基础概念、使用方法、常见实践和最佳…...

上位机知识篇---DDSSDK

文章目录 前言第一部分&#xff1a;DDS核心特性1.以数据为中心2.发布-订阅模型3.质量服务4.多语言支持 关键概念1.主题2.发布者3.订阅者4. 数据写入者5.数据读取者6.域参与者7.域 DDS的优势1.可伸缩性2.实时性3.可靠性4.容错性 DDS的应用场景1.军事通信系统2.航空航天3.工业自动…...

基于DeepSeek在藏语学习推广和藏语信息化方面可以做哪些工作?

基于DeepSeek对藏语的技术优势&#xff0c;您可在以下三大方向开展创新性工作&#xff0c;以下是20具体落地方案&#xff1a; 一、藏语智能教育工具开发 《三十颂》AI语法教练 开发虚拟助教自动解析藏文句子结构&#xff08;标注格助词/时态变化&#xff09;错误检测系统&…...

如何把obsidian的md文档导出成图片,并加上文档属性

上篇关于这个插件PKMer_Obsidian 插件&#xff1a;Export Image plugin 一键将笔记转换为图片分享的文章 如何把obsidian的md文档导出成图片&#xff0c;并加上水印-CSDN博客 如何导出图片的时候让文档属性也显示出来&#xff0c;啊啊&#xff0c;这个功能找了一晚上&#xf…...

AUTOSAR从入门到精通-车身控制系统BCM(三)

目录 前言 算法原理 什么是车身控制模块BCM 1. BCM ECU的工作原理 a. 硬件架构 b. 控制逻辑 BCM带来的好处 车身控制模块(BCM)的功用 车身控制模块(BCM)能够控制的车身功能系统 BCM的各项功能 1.1内外部灯光控制 1.2 雨刮系统 1.3 车身防盗报警系统 1.4 车锁…...

删除全表数据sql

-- 删除 employees 表中的所有数据 DELETE FROM employees;-- 清空 employees 表中的所有数据 TRUNCATE TABLE employees;TRUNCATE 操作不记录每一行的删除操作&#xff0c;而是直接释放数据页&#xff0c;所以执行速度通常比 DELETE 快。不过它不能和 WHERE 子句一起使用&…...

Winform如何取消叉号,减号和放大(两种)

方法一: 找到窗体属性 MaximizeBoxFalse; MinimizeBoxFalse; ControlBoxFALSE; 方法二: 点击Form 在From里面找到Form-Closing 这个事件 写入 if(e.CloseReasonCloseReason.UserClosing) { MessageBox.Show("对不起,你不能关闭") e.Cancel true; }...

Couchbase UI: Query

Couchbase 的 Query 页面在 UI 中是一个核心功能模块&#xff0c;支持 N1QL 查询的编写、调试和优化。同时&#xff0c;它也扩展了与查询相关的功能&#xff0c;比如 Workbench、Monitor 和 UDF 管理。这些功能让开发者和管理员能够更加高效地管理数据查询和性能优化。 以下是…...

Word 中实现方框内点击自动打 √ ☑

注&#xff1a; 本文为 “Word 中方框内点击打 √ ☑ / 打 ☒” 相关文章合辑。 对第一篇增加了打叉部分&#xff0c;第二篇为第一篇中方法 5 “控件” 实现的详解。 在 Word 方框内打 √ 的 6 种技巧 2020-03-09 12:38 使用 Word 制作一些调查表、检查表等&#xff0c;通常…...

Go优雅实现redis分布式锁

前言 系统为了保证高可用&#xff0c;通常会部署多实例&#xff0c;并且会存在同时对共享资源并发读写&#xff0c;这时候为了保证读写的安全&#xff0c;常规手段是会引入分布式锁&#xff0c;本文将介绍如何使用redis设计一个优雅的Go分布式锁。 设计 redis分布式锁是借助…...

A7. Jenkins Pipeline自动化构建过程,可灵活配置多项目、多模块服务实战

服务容器化构建的环境配置构建前需要解决什么下面我们带着问题分析构建的过程:1. 如何解决jenkins执行环境与shell脚本执行环境不一致问题?2. 构建之前动态修改项目的环境变量3. 在通过容器打包时避免不了会产生比较多的不可用的镜像资源,这些资源要是不及时删除掉时会导致服…...

Controller 层优化四步曲

Controller 层优化四步曲 前言 在开发过程中&#xff0c;Controller 层作为系统与外界交互的桥梁&#xff0c;承担着接收请求、解析参数、调用业务逻辑、处理异常等职责。 然而&#xff0c;随着业务复杂度的增加&#xff0c;Controller 层的代码往往会变得臃肿且难以维护。 …...

自动化运维在云环境中的完整实践指南

随着云计算的普及,越来越多的企业将业务迁移到云上。云环境的高动态性和复杂性使得传统的手动运维方式难以应对,自动化运维成为提升效率、降低成本、保障系统稳定性的关键。本文将详细介绍如何在云环境中实施自动化运维,涵盖工具选择、实施步骤和最佳实践。 © ivwdcwso…...

electron typescript运行并设置eslint检测

目录 一、初始化package.json 二、安装依赖 三、项目结构 四、配置启动项 五、补充&#xff1a;ts转js别名问题 一、初始化package.json 我的&#xff1a;这里的"main"没太大影响&#xff0c;看后面的步骤。 {"name": "xloda-cloud-ui-pc"…...

DiffuEraser: 一种基于扩散模型的视频修复技术

视频修复算法结合了基于流的像素传播与基于Transformer的生成方法&#xff0c;利用光流信息和相邻帧的信息来恢复纹理和对象&#xff0c;同时通过视觉Transformer完成被遮挡区域的修复。然而&#xff0c;这些方法在处理大范围遮挡时常常会遇到模糊和时序不一致的问题&#xff0…...

《Operating System Concepts》阅读笔记:p1-p1

《Operating System Concepts》学习第 1 天&#xff0c;p1-p1 总结&#xff0c;总计 1 页。 一、技术总结 无。 二、英语总结(生词&#xff1a;1) 1.intermediary (1)intermediary: inter-(“between, among”) medius(“middle”) c.intermediary originally referred …...

9.8 实战:使用 GPT Builder 开发定制化 ChatGPT 应用

实战:使用 GPT Builder 开发定制化 ChatGPT 应用 引言:打造属于你的智能助手 定制化 ChatGPT 应用正在成为解决具体问题和提升生产力的关键工具。GPT Builder 提供了一个灵活、直观的平台,让开发者和非技术用户都能快速创建满足特定需求的智能助手。本文将通过一个实战案例…...

团体程序设计天梯赛-练习集——L1-024 后天

前言 首先祝大家新年快乐&#xff0c;然后博主今点炮让炮崩了一下&#xff0c;水一天 这道题5分非常简单&#xff0c;有不少的做法 L1-024 后天 如果今天是星期三&#xff0c;后天就是星期五&#xff1b;如果今天是星期六&#xff0c;后天就是星期一。我们用数字1到7对应星期…...

基于STM32的智能语音控制灯光系统设计

目录 引言系统设计 硬件设计软件设计 系统功能模块 语音识别模块灯光控制模块模式切换与场景管理模块用户交互与显示模块远程控制与数据上传模块 控制算法 语音识别与命令解析算法灯光强度与颜色调节算法数据记录与远程反馈算法 代码实现 语音识别与灯光控制代码场景模式与定时…...

Redis部署方式全解析:优缺点大对比

Redis部署方式全解析&#xff1a;优缺点大对比 一、引言 Redis作为一款高性能的内存数据库&#xff0c;在分布式系统、缓存、消息队列等众多场景中都有着广泛的应用。选择合适的Redis部署方式&#xff0c;对于系统的性能、可用性、可扩展性以及成本等方面都有着至关重要的影响…...

Java实现FIFO缓存策略实战

实现FIFO模型选择FIFO模型实现过程FIFO模型完整代码下面看一下先进先出的示例过程总结FIFO(First In First Out,先进先出)策略是一种基本的数据处理和存储管理方法,在Java中,这种策略通常用于管理那些需要按照顺序处理的数据项,比如任务的队列、数据的传输缓冲区等。在Ja…...

把markdown转换为pdf的方法

将 Markdown 文件转换为 PDF 有多种方法&#xff0c;以下是几种常见的方式&#xff1a; 1. 使用 VS Code 和 Markdown 插件 VS Code 是一款流行的代码编辑器&#xff0c;支持通过插件将 Markdown 转换为 PDF。 步骤&#xff1a; 安装 VS Code&#xff1a; 下载地址&#xff…...

Java Web 开发基础介绍

Java学习资料 Java学习资料 Java学习资料 一、引言 在当今数字化时代&#xff0c;Web 应用无处不在。Java 凭借其强大的功能、良好的跨平台性和丰富的开发框架&#xff0c;成为 Web 开发领域的热门选择之一。Java Web 开发允许开发者构建动态、交互式的 Web 应用程序&#x…...

自定义数据集,使用 PyTorch 框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

在本文中&#xff0c;我们将展示如何使用 NumPy 创建自定义数据集&#xff0c;利用 PyTorch 实现一个简单的逻辑回归模型&#xff0c;并在训练完成后保存该模型&#xff0c;最后加载模型并用它进行预测。 1. 创建自定义数据集 首先&#xff0c;我们使用 NumPy 创建一个简单的…...

LangChain概述

文章目录 为什么需要LangChainLLM应用开发的最后1公里LangChain的2个关键词LangChain的3个场景LangChain的6大模块 为什么需要LangChain 首先想象一个开发者在构建一个LLM应用时的常见场景。当你开始构建一个新项目时&#xff0c;你可能会遇到许多API接口、数据格式和工具。对于…...

Ubuntu 16.04安装Lua

个人博客地址&#xff1a;Ubuntu 16.04安装Lua | 一张假钞的真实世界 在Linux系统上使用以下命令编译安装Lua&#xff1a; curl -R -O http://www.lua.org/ftp/lua-5.3.3.tar.gz tar zxf lua-5.3.3.tar.gz cd lua-5.3.3 make linux test 安装make 编译过程如果提示以下信息…...

独立开发者产品日刊:将 Figma 设计转化为全栈应用、对话 PDF生成思维导图、视频转 AI 笔记、AI问答引擎、Mac 应用启动器切换器

独立开发者产品日刊&#xff0c;每日汇集 ProductHunt 热榜产品介绍&#xff0c;用一个 Slogan 帮你概括产品内容&#xff0c;期望能够让你快速浏览get最新产品创意&#xff0c;激发在产品上的灵感。 Lovable Builder.io Slogan&#xff1a;将 Figma 设计转化为全栈应用 类别…...

【算法】经典博弈论问题——威佐夫博弈 python

目录 威佐夫博弈(Wythoff Game)【模板】 威佐夫博弈(Wythoff Game) 有两堆石子&#xff0c;数量任意&#xff0c;可以不同&#xff0c;游戏开始由两个人轮流取石子 游戏规定&#xff0c;每次有两种不同的取法 1)在任意的一堆中取走任意多的石子 2)可以在两堆中同时取走相同数量…...

Julius AI 人工智能数据分析工具介绍

Julius AI 是一款由 Casera Labs 开发的人工智能数据分析工具&#xff0c;旨在通过自然语言交互和强大的算法能力&#xff0c;帮助用户快速分析和可视化复杂数据。这款工具特别适合没有数据科学背景的用户&#xff0c;使数据分析变得简单高效。 核心功能 自然语言交互&#x…...

SpringBoot+Electron教务管理系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1.查询课程表代码2.保存学生信息代码3.用户登录代码 一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBootElectron框架开发的教务管理系统。首先&#xff…...

1.23学习记录

web XYNU2024信安杯 哎~想她了 源代码找到提示&#xff0c;访问页面第一层数组绕过&#xff0c;第二层发现ls /可以执行&#xff0c;接着用less代替tac和cat less /fl[a-z]g exp&#xff1a; URL/?fj1[]1&fj2[]2&cmdless /fl[a-z]gmisc [SWPU 2020]套娃 下载附件…...

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(三)

Understanding Diffusion Models: A Unified Perspective&#xff08;三&#xff09; 文章概括 文章概括 引用&#xff1a; article{luo2022understanding,title{Understanding diffusion models: A unified perspective},author{Luo, Calvin},journal{arXiv preprint arXiv:…...

NeetCode刷题第17天(2025.1.27)

文章目录 086 Course Schedule II 课程安排二087 Graph Valid Tree 图有效树088 Number of Connected Components in an Undirected Graph 无向图中的连接组件数量 086 Course Schedule II 课程安排二 您将获得一个数组 prerequisites &#xff0c;其中 prerequisites[i] [a,…...

Seed Edge- AGI(人工智能通用智能)长期研究计划

Seed Edge 是字节跳动豆包大模型团队推出的 AGI&#xff08;人工智能通用智能&#xff09;长期研究计划12。以下是对它的具体介绍1&#xff1a; 名称含义 “Seed” 即豆包大模型团队名称&#xff0c;“Edge” 代表最前沿的 AGI 探索&#xff0c;整体意味着该项目将在 AGI 领域…...

企业知识管理推动企业整体效能提升与创新能力发展的路径探索

内容概要 企业知识管理是指通过对组织内外部知识的识别、获取、整合与应用&#xff0c;提升企业整体运营效能与竞争力的一系列管理活动。其重要性在于&#xff0c;知识作为一种无形资产&#xff0c;能够显著影响企业的决策质量和创新能力。在当今快速发展的市场环境中&#xf…...

【gopher的java学习笔记】一文讲懂controller,service,mapper,entity是什么

刚开始上手Java和Spring时&#xff0c;就被controller&#xff0c;service&#xff0c;mapper&#xff0c;entity这几个词搞懵了&#xff0c;搞不懂这些究竟代表什么&#xff0c;感觉使用golang开发的时候也没太接触过这些名词啊~ 经过两三个月的开发后&#xff0c;逐渐搞懂了这…...

ZZNUOJ(C/C++)基础练习1000——1010(详解版)

目录 1000 &#xff1a; AB Problem C语言版 C版 1001 &#xff1a; 植树问题 C语言版 C版 1002 &#xff1a; 简单多项式求和 C语言版 C版 1003 &#xff1a; 两个整数的四则运算 C语言版 C版 1004 &#xff1a; 三位数的数位分离 C语言版 C版 补充代…...

volatile之四类内存屏障指令 内存屏障 面试重点 底层源码

目录 volatile 两大特性 可见性 有序性 总结 什么是内存屏障 四个 CPU 指令 四大屏障 重排 重排的类型 为什么会有重排&#xff1f; 线程中的重排和可见性问题 如何防止重排引发的问题&#xff1f; 总结 happens-before 和 volatile 变量规则 内存屏障指令 写操作…...