项目复杂业务的数据流解耦处理方案整理
目前项目中使用mobx,项目比较久了,每个Store的内容是越来越多了,逻辑也是越来越复杂,如果不梳理估计以后模块的层级会很乱。
之前整理了一些数据流管理的对比实践和最佳方案的梳理,最后写来写去感觉还是要整理一个架构层级的梳理,不然没有办法治理现在的问题:
- 单个数据流管理无限膨胀。
- 数据流Store职责不清晰,相互调用无法解耦。
- 各种数据瞎提升,没有一个清晰的约束。
- UI数据和逻辑数据耦合。
具体的层级架构图因为一些保密性的原因就不展示了,最后梳理的结果是一个非常大的工程,但是在这个思考过程中也受到了非常多的代码启发,将一些经验和体会记录在这。
下面的部分是到处抄出来的,有一些逻辑不通顺的地方八成是反复修改框架图造成的。
参考
- https://phodal.github.io/clean-frontend/
- https://cn.mobx.js.org/best/store.html
- 精读《对前端架构的理解 - 分层与抽象》
- https://www.tangshuang.net/8212.html
- 这可能是大型复杂项目下数据流的最佳实践
- https://juejin.cn/post/7141210516101759013?searchId=2025011220230401FF03ACE5F349C6457A
- https://juejin.cn/post/6844903498266443789?searchId=20250112194820475FC27215758EBC7A4F
术语介绍 & 划分逻辑
1. MVVM和MVC工程理念
MVC:
Model-View-Controller(模型-视图-控制器) 模式,这种模式可以理解为:Controller负责将Model的数据用View显示出来。它是一种单向数据流管理。
MVVM:
Model-ViewModel-View模式,MVC的进阶版,ViewModel在其中起到了双向绑定的作用,解耦了View层直接读取Model层,并且ViewModel实现了View和Model的自动同步,使开发者不必再去关心交互时的同步问题,或者直接操作DOM节点,更专注于数据逻辑的处理。
在本文中,层级结构以MVVM的分层理念作为划分基础,但是在架构中我们不会感知到一个具体的Model层级的存在。
在项目中,我们概念上的“Model”应该是一个个“Store”,它包含了数据和业务逻辑的整合。而概念中的“ViewModel”应该是框架中负责双向通知的部分,即:Mobx-React工具(负责响应式的数据通知UI更新)、Mobx中的observable和computed、action等,它们都用于Model和View之间进行数据同步和事件处理。
Model和ViewModel在实际实现中无法区分,但是在框架层级中又必须体现,尤其是viewModel这块怎么管理数据流必须要定义清楚,因此其实并不是非常严格地遵循MVVM,只是作一个大方向上的指引。
2. 模块依赖关系处理-依赖反转原则(SOLID原则)
模块依赖关系处理是我们项目中的一个难题,因为我们常常互相调用、公共调用方法。在复用层面这是不可避免的。我们知道分层可以解耦,对降低复杂度非常有效。那我们是否也可以对 Store 也进行分层,且约束他们之间互相调用?
但是分层调用,就涉及到一个问题:模块依赖关系如何处理?
稳定依赖
假设我们分层,那就会出现这样的依赖场景:
模块D被A、B、C同时依赖,修改模块D的同时将影响A、B、C三个模块,这不仅没有解耦,完全是在给模块找个麻烦。上述场景中,我们肯定希望D模块是稳定的,因为改它的成本比改子模块高多了。所以在设计之初,我们就应当遵守 稳定依赖原则,即依赖关系必须要指向更加稳定的方向。
一般来说,每个项目不稳定的原因都来自于需求变更,那么可以说更加靠近业务侧的偏向于不稳定,而远离业务侧的则偏向于稳定。
设计一个更稳定的系统,区分模块是否稳定很重要,因为模块D如果混入了不稳定的逻辑,它将为整个系统构造带来隐患。但是在开发中我们经常会发现,A、B、C当中确实存在复用却不稳定的逻辑方法。
这种时候应该怎么设计比较好呢?
依赖反转原则
SOLID原则提出了五个稳定性原则,都可以用于指导我们的代码开发和模块规划,本文章讨论的只是其中一个“依赖反转原则”。它将在我们Store模块解耦规划中发挥重要作用。
依赖反转原则的核心思想是,高层模块不应该依赖于低层模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。这旨在减少模块间的耦合,使得系统更容易修改和扩展。
By GPT
对于这种情况,我们可以打破ABC和D之间的依赖关系,在中间新增一个中间的抽象模块。这时候依赖关系就变成了下图所示。
E中是A、B、C中的复用方法的抽象,A、B、C是方法的具体实现,修改需求时我们只修改具体实现,而复用的抽象逻辑是稳定不变更的。
这样一来,ABC共同依赖于E,E模块也是一个稳定的模块,所以这也符合稳定依赖原则。
说回到项目中的耦合问题,目前我们的项目中store是同层级的,因此会有下面这样的互相调用,这样就会导致单个模块的不稳定:假如原本A模块的复杂度是n,它又调用了B模块的方法,导致它的调用链条增长,A模块的复杂度是倍数上升的,2*n,再假如B又调用了C的方法,当你改动到A模块的功能时,为了确定影响范围,要了解所有的调用链条,就要去找A、B、C三个模块才能得到结果。
模块之前相互依赖导致的问题:
- 依赖链条太长。
- 影响范围不清晰,一个功能的内部涉及到多个复杂模块,功能高度聚合,以后想复用、迁移、扩展都会非常麻烦。
因此,我们希望最小层级之间的A、B是一个功能明确的单一模块。我们知道分层可以解耦,对降低复杂度非常有效。那我们是否也可以对 Store 也进行分层来约束他们之间互相调用?
对分出来的root层有如下约束: - root内的方法必须是抽象的、单例的、最小粒度的,而业务功能的具体实现和方法的组装则细化到具体的功能模块中。
- 保持root的稳定性,作为一个共有依赖模块,它的维护决定了整个项目的复杂度。
- 同层调用仍然存在调用链不明晰的风险,但是这个风险变得可控,唯独牢记一点:决不允许跨层调用。
- 父依赖root不能调用任何子模块的方法。
- 其他中心的子模块不能直接调用父级依赖方法,只能同层级调用其他功能模块中已经具体实现的功能方法。
3. 数据全局化和划分粒度
上面是Store架构的介绍,但是落实到具体的页面场景中它的划分粒度还是太“粗犷”,我们在开发时经常会有一个疑惑:有一个公共数据,我该放在哪里?是Store里,还是页面里,还是组件里;而放置后,我又该如何通信?如果不划分好这一点,架构层级将无法落实到开发实际中。
在我们的项目中目前存在如下问题:
- 只要是共享数据就提升全局,导致全局状态逻辑混乱。
- UI数据和业务逻辑杂糅。
通信
在非父子组件之间共享传递一些状态,我们会使用状态提升来解决这个问题。但是如果此时组件之间的嵌套过深,那么中间经过的组件都会帮忙传递这些无用的 props, 且如果需要传递参数或者增加 props ,都需要修改 A、B、中间组件 * n 个地方。
一些时候,只要是跨组件的数据状态,我们都会提升到全局Store中,久而久之,Store的数据越来越多,难以治理。
React 官方的指导意见:如果多个 Component 之间要发生交互, 那么数据就维护在这些 Component 的最小公约父节点上。
但是,实际开发中,就像下图,多个节点之间共有可以提取的Store很多。
太多的状态提升不利于项目管理,而且我们页面的组件数据层级也不算很深,没必要搞太多的小型Store出来。
不过这部分组件通信的共享数据如果放到全局Store中也并不合适。那么,又像上面所说,新增分层去解决这个问题,演进如下,新增了PageStore的层级。为了减少mobx全局和页面级Store之间易于混淆的地方,我们项目中的PageStore使用context去实现。
页面级的数据复杂度应该可以满足目前的要求,所以也就不再分成更细粒度的组件Store层。
数据类型与存放
上面介绍了最终的状态管理层级,那么,问题又来了:我们怎么区分一个数据应该放哪里,我想这是开发者最关心的问题。
目前我们将项目数据分为了三类型:(1就不讨论了,重点是2、3)
- 全局数据。
- 业务数据。(业务逻辑数据)
- UI数据。(UI视图数据,比如domVisible,domRef等等)
目前我们的项目Store里的数据业务数据和UI数据杂糅,看到很多最佳实践里面都推荐去具体细化数据类型,拆分视图数据和业务数据。
观察了一下,一些推荐的拆分方案一般是将数据+行为提取为一个抽象的功能模块,它是一个提供功能服务的模块,但是并不是Store。比如现在我们要控制页面上导航的高度,以往我们会放在mobx中,但是,按照UI逻辑解耦的方案,我们可以考虑将导航的整个控制功能抽象为一个功能模块,这个模块中包含如下的数据和使用方法:
- 导航的DOM节点,可以方便控制。
- 控制导航显示隐藏,和内部模块的显示隐藏。
- 控制导航高度等等。
按照如上的公共功能模块抽离,同样解决了UI层逻辑复用的问题。
上面介绍了一种解耦UI层和Store层的方案,但是在我们项目目前的实际开发中,并不打算一次性做的这么分离。高内聚和低耦合当然是好的,但是如果不划分内聚和解耦的粒度,也会带来很多的麻烦。
不打算做UI和业务数据的层级分离的原因:
- 增加了开发时的心智负担,在开发前需要做好详细设计。
- 目前我们的项目涉及到的这个层面的杂糅并不是当前项目的主要问题。
- 可以作为日后优化的保留迭代项目。
4. DDD(Domain-Driven Design)领域模型
书面化的说法:领域驱动设计(DDD)运用全域内的软件模型与其核心理念相结合的方式,进一步应对复杂数据及其综合系统分析的基础用法。
它是一种治理复杂数据耦合的架构设计理念,其实具体很复杂,不同的人理解下的 DDD 也会有所差异,它还包括了一系列如何划分领域模型的方法论,我也没有深入了解。
它提出了一种“领域模型”的概念,又可以称之为“实体(entity)”,实体可以是拥有方法的对象,也可以是数据结构和函数的集合。在我们的项目中,实体指的是应用里的业务对象,即实体封装了商城的核心业务逻辑,并且抽象成通用的实体服务。规则抽象成实体服务后,任何操作层面的改动都不会影响到这一层。
在这里介绍DDD,一是它可以作为架构分层的划分依据,二是用于指导我们的开发逻辑复用处理,帮助我们更好地维护项目。
如果一个重复逻辑在项目中反复出现,那么它就是一个可以复用的逻辑,这时候我们可以把它抽象为方法、hook等,但如果是一个复杂的逻辑、包括逻辑中存在的数据,在项目中被反复使用,我们应该怎么去维护这个数据结构呢?
是的,我们可以把它抽象为一个领域模型(实体,或者class类),其实我们项目中目前很多这种大量的“实体”服务,这些都是领域模型的一种。
抽象出来的“领域模型”是一个复用性很高、具有高度稳定性的结构组合,有了这样一个稳定的领域模型,视图层只需要实现视觉稿和组装业务逻辑,具备很强的灵活性,就好像搭积木一样,底层的领域模型不需要变动,只需要改动交互变更或视图。极大提升了开发效率和维护性。
最后形成的框架图示意
UI页面 / 组件⬆️ ↖️pageStore / LayoutStore ⬅️ api层 ⬅️ api防腐层 ⬅️ 后端接口⬆️ ↙️moduleStore ⬅️ service ↙️————————————————————————————⬆️ ⬆️ 各种功能系统*⬆️ ⬆️ 基础config,libs,utils等```
解释说明
PageStore(ViewModel)
页面级的Store层级。
作用
- 明确当前页面的影响范围。
- 解耦UI数据和业务数据。
- 明确使用依赖,有利于按需初始化所需的ModuleStore。
- 解开ModuleStore之间的相互调用。
开发说明
- 每个页面专有的状态管理,放置于当前页面的文件夹内。
- 内部注入所需的ModuleStore,页面组件内以PageStore.Module.observabelData方式使用。
- 公共组件被多个页面使用,应该在设计公共组件时就考虑做成无状态的公共组件,所有的业务方法从外部传入,这样才能被PageStore控制。
ModuleStore
根据各个功能模块划分的Store。
数据流顺序为PageStore -调用-> ModuleStore ,不允许反向调用。
开发说明
- 业务相关的数据、方法放在Module,划分依据如下:
- 如果一个数据由接口获得,则必然是业务数据。
- 如果拿不准一个数据是不是业务数据,则建议优先放在moduleStore中,因为PageStore渲染数据时可以调用功能模块,但是功能模块需要某个数据时不能反向调用。
- 功能模块的相互调用通过RootStore,但是只允许全局类型的Store,功能模块之间的相互调用通过上层PageStore的聚合。
- 方法使用Promise便于上层控制。
废稿说明
在上面的划分逻辑中其实我有两个概念在最后真正成型的架构图中被舍弃了。
1. RootStore
上面在“稳定依赖”目录下,说过两个耦合的功能模块中提取出公共模块moduleRootStore,这个父层级的Store会被定义为抽象模块,可以被单功能依赖。
实际可能出现的问题:
- 父层级的功能抽离不出来,对开发个人的要求比较高,而且要提前设计好复用能力。
- 超复杂的模块依赖被我们亲手创建出来了(😂)。随着业务扩展,肯定会有越来越多的东西堆在这个新的父层级里,最后父层级既无法做到“稳定”,又无法做到“公共”,变成了整个项目里最复杂的部分,而且改动它将影响下面所有依赖它的子moduleStore。
- 没有办法真正地解决我们模块功能耦合的问题。
解决办法
将moduleStore的耦合功能,直接提升层级解耦,提出了PageStore的层级。PageStore去组合、调用moduleStore的功能,PageStore的使用逻辑很明确,而且不存在往里面丢垃圾的情况(毕竟它只做调度不做真正的业务功能处理)。
2. 不处理UI数据
上面的“数据类型与存放”里面,写了很长的一段话说暂时不想改UI数据的存放位置,还是放在ModuleStore里面,但是提取出PageStore之后这个问题也可以迎刃而解了。
页面 / 组件的UI处理关我功能Store什么事呢?
页面 / 组件的UI数据放到PageStore里面,如果有全局公共的就放到LayoutStore里面。
相关文章:
项目复杂业务的数据流解耦处理方案整理
目前项目中使用mobx,项目比较久了,每个Store的内容是越来越多了,逻辑也是越来越复杂,如果不梳理估计以后模块的层级会很乱。 之前整理了一些数据流管理的对比实践和最佳方案的梳理,最后写来写去感觉还是要整理一个架构…...
手部穴位检测技术:基于OpenCV和MediaPipe的实现
手部穴位检测是医学和健康管理领域的重要技术之一。通过准确识别手部的关键穴位,可以为中医诊断、康复治疗以及健康监测提供支持。本文将介绍一种基于OpenCV和MediaPipe的手部穴位检测方法,展示如何利用计算机视觉技术实现手部关键点的检测,并进一步标注手部的穴位位置。 技…...
Pycharm 启动时候一直扫描索引/更新索引 Update index/Scanning files to index
多个项目共用一个虚拟环境,有助于加快PyCharm 启动吗 chatgpt 4o认为很有帮助,gemini 2.5pro认为没鸟用,我更认可gemini的观点。不知道他们谁在一本正经胡说八道。 -------- 打开pycharm的时候,下方的进度条一直显示在扫描文件…...
解锁健康密码,拥抱品质生活
在生活节奏不断加快的今天,健康养生已成为人们关注的焦点。它不仅关乎当下生活质量,更是对未来幸福的投资。从日常生活的点滴出发,掌握正确养生方法,我们就能轻松收获健康。 饮食是健康的基石。我们应当遵循 “食物多样&#x…...
安卓开发工程师- Intent 机制
Intent 的作用是什么? Intent(意图)是 Android 中用于组件之间通信的一种机制。它主要用于以下几种场景: 启动 Activity:从一个 Activity 跳转到另一个 Activity。启动 Service:用于启动后台服务或与服务…...
iOS 使用 - 修改屏幕为黑白显示(墨水屏)
iOS 18 设置 – 辅助功能 – 显示与文字大小 – 色彩滤镜 打开色彩滤镜,选择 灰度,最下方调节 强度值 怀念起那个用电子词典的岁月,一个个字母键入,就可以获得很多知识。 触屏时代,一切好像更简单了,但也更…...
小白速通:Verilog流水线实现及时序分析
目录 题目:时序分析:时钟频率为50MHz数据1: a10, b20, c30, d40, e2数据2: a5, b15, c25, d35, e3数据3: a8, b12, c16, d24, e4 流水线效率分析 题目: verilog中,y(abcd)*e,时钟频率为50Mhz,用流水线的形式…...
微软的 Copilot 现在可以浏览网页并为您执行操作
在庆祝其 50 岁生日之际,微软正在向其人工智能驱动的 Copilot 聊天机器人传授一些新技巧。 从 BASIC 到 AI,改变世界的公司:微软 微软表示,Copilot 现在可以在“大多数网站”上采取行动,使其能够预订门票、预订餐厅等…...
【C++】vector的模拟实现
文章目录 前言一. vector的底层二. 关于容量和大小的函数2.1 size和capacity2.2 reserve2.3 resize2.4 empty 三. vector的默认成员函数3.1 构造函数3.1.1 无参构造函数3.1.2 构造初始化为n个val值3.1.3 用initializer_list构造初始化3.1.4 使用迭代器区间进行构造初始化 3.2 拷…...
C# Winform 入门(9)之如何封装并调用dll
封装dll 首先创建 .Net平台 类库 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace _09.Encapsulation_dll {public class Program{/// <summary>/// 求两个double类型的数值的和/// &l…...
【C语言】内存函数
大家好,很高兴又和大家见面了!!! 在C语言标准库中,有一些直接对内存进行操作的函数,我们将其称之为内存函数,这些函数位于头文件<string.h>,在网站https://cplusplus.com/ref…...
SDL视频显示函数
文章目录 1. **`SDL_Init()`**2. **`SDL_CreateWindow()`**3. **`SDL_CreateRenderer()`**4. **`SDL_CreateTexture()`**5. **`SDL_UpdateTexture()`**6. **`SDL_RenderCopy()`**7. **`SDL_RenderPresent()`**8. **`SDL_Delay()`**9. **`SDL_Quit()`**总结示例代码:代码说明:…...
博客文章:深入分析 PyMovie - 基于 Python和 MoviePy 的视频管理工具
这是一个使用 wxPython 构建界面、moviepy 处理视频的自定义 GUI 应用程序。该工具提供了视频播放、元数据提取、格式转换、视频裁剪和截图等功能。通过分析其设计和实现,我们将了解其工作原理、优点和潜在的改进空间。 C:\pythoncode\new\output\pymovieSample.py …...
Redis中AOF的实现方式和AOF重写
一、AOF 的实现方式 核心原理 AOF 通过将写操作命令以追加方式记录到日志文件中,重启时通过重放命令恢复数据。与 RDB 的快照机制不同,AOF 是增量记录,更适用于数据一致性要求较高的场景。写入流程 命令执行:客户端发送写命令&am…...
Supervisor的安装和使用
Supervisor 使用笔记(CentOS 8 环境) 本周,老师让我使用supervisor管理项目服务,当时第一次听说过这个进程管理工具😶🌫️,就上网搜了搜安装和使用,又用ai查了一些细节࿰…...
JVM 内存区域详解
JVM 内存区域详解 Java 虚拟机(JVM)的内存区域划分为多个部分,每个部分有特定的用途和管理机制。以下是 JVM 内存区域的核心组成及其功能: 一、运行时数据区(Runtime Data Areas) 1. 线程共享区域 内存…...
【java】在 Java 中,获取一个类的`Class`对象有多种方式
在 Java 中,获取一个类的Class对象有多种方式。Class对象代表了 Java 中的一个类或接口的运行时类信息,可以用于反射操作。以下是获取Class对象的几种常见方法: 1.使用.class属性 每个类都有一个.class属性,可以直接获取该类的Cl…...
蓝桥杯:对字符串处理常用知识笔记
一、前面四个是计算带有空格字符串的的长度计算 C语言代码 #include<string.h> #include<stdio.h> int main() { char s[105]; gets(s); printf("%d", strlen(s)); return 0; } 算法2 C 代码(常用) #include <iostream> #in…...
c++网络编程,信号透传可能是什么意思
在 C 网络编程中,**信号透传**(Signal Pass-Through)通常 refers to the concept of allowing signals to propagate through a network protocol stack without being interrupted or modified. 具体来说,信号透传可以涉及到几个…...
数据结构与算法学习笔记----贪心·绝对值不等式
数据结构与算法学习笔记----贪心绝对值不等式 author: 明月清了个风 first publish time: 2025.4.5 ps⭐️感觉其实是一个数学的问题, Acwing 104. 货仓选址 [原题链接](104. 货仓选址 - AcWing题库) 在一条数轴上有 N N N家商店,他们的坐标分别为 A…...
CUDA学习--体验GPU性能
学习来源:2 CUDA Python--并行计算基础-卷积计算以及共享内存_哔哩哔哩_bilibili 处理一张图片的处理速度对比 import cv2 from numba import cuda import time import math cuda.jit() def process_gpu(img,channels):tx cuda.blockIdx.x*cuda.blockDim.xcuda…...
博途 TIA Portal之1200做主站与200SMART的S7通讯
有时候,我们与之作S7通讯的西门子系PLC并不是同一个厂商或是同一时期供货的,也有可能不在一个编程软件中。此时进行S7能讯会有所不同。本文将演示博途与200SMART做S7通讯。 1、硬件准备 1200PLC一以,200SMART一台,网线2根,交换机一台。 2、关于编程 1200做主站,因此需…...
a标签download下载图片
a标签的download属性是HTML5中新增的一个属性,用于指定链接点击时直接下载文件,而不是在浏览器中打开文件。 基本用法 指定下载文件名:在a标签中添加download属性,并指定一个文件名。例如: <a href"…...
#SVA语法滴水穿石# (013)关于 disable iff、matched 、expect 的用法
SystemVerilog 断言(SVA)中 disable iff、matched 和 expect 的语法知识。 1. disable iff (condition) 功能与定义 作用:当指定条件(condition)为真时,禁用当前属性的检查。 常用于复位(rese…...
Day2-2:前端项目uniapp壁纸实战
再在wallpaper新建一个目录components 在components下新建组件common-title 记得点击创建同名目录 在index加 <view class"select"><common-title></common-title></view> 图片换了下,原来的有点丑,图片可按自己喜欢…...
pycharm如何通过跳板机连接服务器在本地debug
现在假设你有一个服务器,需要跳板机登陆,但是你从跳板机到服务器,只知道能直接通过ssh连接。 首先你可以现在本地创建一个 SSH 配置文件(~/.ssh/config): Host jumpHostName 跳板机地址Port 端口User 用户…...
Mysql explain中列的解析
EXPLAIN列的解释: table:显示这一行的数据是关于哪张表的 type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL possible_keys:查询可以利用的索引&#…...
场馆预定系统小程序PHP+uniapp
场馆预定系统小程序:基于PHPUniApp的多场景体育场馆智慧化解决方案 随着全民健身意识的提升,体育场馆的数字化管理需求日益增长。场馆预定系统小程序凭借其轻量化、高便捷性,成为体育馆、羽毛球馆、兵乒球馆等场所提升运营效率的核心工具。本…...
05.unity 游戏开发-3D工程的创建及使用方式和区别
05.unity 游戏开发-3D工程的创建及使用方式和区别 提示:帮帮志会陆续更新非常多的IT技术知识,希望分享的内容对您有用。本章分享的是Python基础语法。前后每一小节的内容是存在的有:学习and理解的关联性,希望对您有用~ unity简介…...
php8 命名参数使用教程
简介 PHP 8 引入 命名参数(Named Arguments),允许在调用函数时按参数名传递值,而不是按照参数位置。这增强了代码的可读性、灵活性,并减少参数顺序依赖。 基本用法 传统位置参数(Positional Arguments&a…...
Transformer与注意力机制详解
1 Transformer与注意力机制详解 本文直观上详细介绍了大语言模型中十分重要的结构——Transformer,及其核心:注意力机制的原理。 1. Transformer结构 基础结构如下图所示,左侧由一系列Encoder block(编码器)构成,接收字词句输入;右侧由一系列Decoder block(解码器)…...
xLua环境控制+xLua的Lua调用C#的1
编写自定义加载器加载指定路径的Lua文件: using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using XLua;//Lua是脚本语言,编写代码脚本是实现功能最重要的方式 public class Loader : MonoBehaviour …...
RabbitMQ应用问题
RabbitMQ应用问题 一.幂等性1.简述概念2.MQ的幂等性介绍3.解决幂等性问题(1)全局唯一ID(2)业务逻辑判断 二.顺序性保障1.简单介绍2.无法保证顺序性的场景3.保障方案1)单队列消费者2)分区消费3)消息确认机制4)业务逻辑控制 三.消息积压问题1.原因分析2.解决方案 一.幂等性 1.简…...
轻量化大模型微调工具XTuner指令微调实战(下篇)
接着上篇文章《轻量化大模型微调工具XTuner指令微调实战(上篇)》来接着写教程。 一、模型转换 模型训练后会自动保存成 PTH 模型(例如 iter_500.pth),我们需要利用 xtuner convert pth_to_hf 将其转换为 HuggingFace…...
Redis数据结构之ZSet
目录 1.概述2.常见操作2.1 ZADD2.2 ZRANGE2.3 ZREVRANGE2.4 ZRANGEBYSCORE2.5 ZSCORE2.6 ZCARD2.6 ZREM2.7 ZINCRBY2.8 ZCOUNT2.9 ZMPOP2.10 ZRANK2.11 ZREVRANK 3.总结 1.概述 ZSet和Set一样也是String类型元素的集合,且不允许重复的成员,不同的是ZSet…...
STM32提高篇: CAN通讯
STM32提高篇: CAN通讯 一.CAN通讯介绍1.物理层2.协议层二.STM32CAN外设1.CAN控制器的3种工作模式2.CAN控制器的3种测试模式3.功能框图三.CAN的寄存器介绍1.环回静默模式测试2.双击互发测试四.CAN的HAL代码解读一.CAN通讯介绍 CAN(Controller Area Network 控制器局域网,简称…...
贪心算法之最小生成树问题
1. 贪心算法的基本思想 贪心算法在每一步都选择局部最优的边,希望最终得到整体最优的生成树。常见的两种 MST 算法为 Kruskal 算法 和 Prim 算法。这两者均满足贪心选择性质和最优子结构性质,即: 贪心选择性质:局部最优选择&…...
C++EasyX之五子棋PVP和PVE
以下是该C EasyX五子棋代码的详细解析: 1 代码 1.1 全代码 #include <graphics.h> #include <conio.h> #include <Windows.h> #include <cmath> #include <vector> #include <tuple> #include <algorithm>using na…...
【Tauri2】015——前端的事件、方法和invoke函数
目录 前言 正文 准备 关键url 获取所有命令 切换主题set_theme 设置大小 获得版本version 名字name 监听窗口移动 前言 【Tauri2】005——tauri::command属性与invoke函数-CSDN博客https://blog.csdn.net/qq_63401240/article/details/146581991?spm1001.2014.3001.…...
【C++奇遇记】C++中的进阶知识(继承(二))
🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集 数据库专栏 初阶数据结构 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如…...
qt designer 软件主题程序设计
对于使用Qt Designer设计的界面,主题切换的实现需要结合Qt的信号槽机制、样式表动态加载以及资源管理。以下是针对Qt Designer UI的详细解决方案: 一、UI文件与主题系统的整合架构 二、核心实现步骤 1. 动态样式表加载系统 // ThemeManager.h class …...
2025 年 4 月补丁星期二预测:微软将推出更多 AI 安全功能
微软正在继续构建其 AI 网络安全战略,并于本月宣布在 Microsoft Security Copilot 中引入新代理。 他们引入了用于网络钓鱼分类的代理、用于数据丢失预防和内部风险管理的警报分类、条件访问优化、漏洞修复和威胁情报简报。 这些代理的目标是不断从这些不同学科中…...
docker swarm常用命令
1、初始化Swarm集群 用于初始化一个Swarm集群,并将当前节点设置为Manager节点。 用法:docker swarm init --advertise-addr <Manager节点IP> # docker swarm init --advertise-addr 192.168.1.100 这会将当前节点初始化为Swarm集群的管理节点&…...
抖音直播位置与IP属地不同?解析原因与应对策略
在当今短视频直播盛行的时代,抖音作为头部平台吸引了大量主播和观众。然而,许多用户发现一个令人困惑的现象:直播间显示的位置信息与账号IP属地不一致。这种情况不仅让观众产生疑问,也可能给主播带来不必要的麻烦。本文将深入分析…...
「限时开源」全网首发!DeepSeek-R1+AI绘画+音乐生成全栈源码
—企业级AIGC私有化终极方案,3大模态整合,成本直降90% 行业痛点:为什么企业急需这套方案? 1. 多模态AIGC的三大困局 成本失控 API吸血: 使用MidjourneyStable DiffusionGPT-4Suno API生成内容,企业月均支…...
设计模式简述(二)单例模式
单例模式 描述基本使用防破坏单例饿汉式懒汉式有上限多例 描述 一个类全局只有一个实例,自行实例化并提供给使用。 构造函数私有化是前提 基本使用 防破坏单例 防反射:在构造函数中判断类中实例是否已初始化 private InnerClassSingleton (){if(Inn…...
区块链钱包:与主流钱包APP的区别
前言 在前端开发者速入:DApp中的前端要干些什么?文中我简单讲解了在DApp中前端开发者要干的是什么,本来在接下来的内容中我应该继续讲解在DApp中前端开发者的一系列工作和其他所要用到的技术栈,但是为了方便后续的讲解,我们这里不得不提及一下在区块链中让无数人又爱又恨…...
23种设计模式-行为型模式-中介者
文章目录 简介问题解决代码架构优势 总结 简介 中介者是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,强制让它们通过一个中介者对象进行合作。 问题 假如你有一个创建和修改用户资料的对话框࿰…...
mysql数据库中getshell的方式总结
mysql数据库中getshell的方式总结 MySQL版本大于5.0,MySQL 5.0版本以上会创建日志文件,我们通过修改日志文件的全局变量,就可以GetSHELL,下面这篇文章主要给大家介绍了关于mysql数据库中getshell的方式,需要的朋友可以参考下 outfile和dumpfile写shell 利用条件 …...
神经网络基础
神经网络的基本组成元素 一个神经元: 单层神经网络: 多层神经网络:(前向计算) 为什么要使用激活函数 如果不使用激活函数,每层只对上层的输入进行线性变换,实际这些线性变换可以归为一层即可。…...