• [技术干货] 软考知识点——计算机中的二进制数运算方法
    计算机中的二进制数运算方法是基于二进制数的位操作实现的,主要包括算术运算(加、减、乘、除)和逻辑运算(与、或、非、异或等)。这些运算是计算机硬件(如CPU中的算术逻辑单元ALU)的核心功能,也是所有高级运算的基础。以下是详细说明:一、算术运算1. 二进制加法规则(按位相加,从最低位开始,逐位进位):0 + 0 = 00 + 1 = 11 + 0 = 11 + 1 = 0(进位1)示例(4位二进制加法): 0101 (5) + 0011 (3) ------- 1000 (8) (无进位溢出)进位处理:若最高位产生进位(如1111 + 0001 = 1 0000),结果需根据位数截断(4位结果为0000,进位标志位设为1)。2. 二进制减法方法:通过补码将减法转换为加法(a - b = a + (-b的补码))。步骤:求减数b的补码(反码加1)。将补码与被减数a相加。若结果产生进位,忽略进位;若无进位且符号位为1,需再次求补码修正结果。示例(4位二进制减法:5 - 3): 0101 (5) - 0011 (3) ------- = 0101 + (补码 of 0011) 0011的反码:1100 补码:1101 0101 + 1101 = 1 0010 → 忽略进位,结果为0010 (2) 3. 二进制乘法方法:类似十进制乘法,通过移位和加法实现。步骤:将乘数的每一位与被乘数相乘(0则结果为0,1则结果为被乘数)。根据乘数位的权重(2的幂次)左移结果。将所有部分积相加。示例(4位二进制乘法:5 × 3): 0101 (5) × 0011 (3) ------- 0101 (5 × 1, 左移0位) + 01010 (5 × 1, 左移1位) ------- 1111 (15) 4. 二进制除法方法:通过试商和减法实现,类似长除法。步骤:从被除数的最高位开始,与除数比较。若被除数部分 ≥ 除数,则商位为1,并减去除数;否则商位为0。左移被除数(带余数),重复步骤2直至所有位处理完毕。示例(4位二进制除法:15 ÷ 3): 1111 (15) ÷ 0011 (3) ------- 1 (商第一位) - 0011 (3) ---- 110 (余数左移) 1 (商第二位) - 0011 (3) ---- 11 (余数左移,不足除,商后续位为0) ------- 商:0101 (5),余数:0011 (3) 二、逻辑运算逻辑运算对二进制数的每一位独立操作,不考虑进位或借位。1. 按位与(AND)规则:对应位均为1时结果为1,否则为0。符号:&示例: 0101 & 0011 = 0001 2. 按位或(OR)规则:对应位至少一个为1时结果为1,否则为0。符号:|示例: 0101 | 0011 = 0111 3. 按位非(NOT)规则:对每一位取反(0变1,1变0)。符号:~示例: ~0101 = 1010 4. 按位异或(XOR)规则:对应位不同时结果为1,相同时为0。符号:^示例: 0101 ^ 0011 = 0110 三、移位运算移位运算通过左移或右移改变二进制数的位序,常用于快速乘除法或数据对齐。1. 逻辑左移(Logical Shift Left)规则:所有位向左移动n位,右侧补0。效果:相当于乘以2^n。示例(逻辑左移1位): 0101 (5) << 1 = 1010 (10) 2. 逻辑右移(Logical Shift Right)规则:所有位向右移动n位,左侧补0。效果:相当于除以2^n(向下取整)。示例(逻辑右移1位): 0101 (5) >> 1 = 0010 (2) 3. 算术右移(Arithmetic Shift Right)规则:符号位保持不变,其余位向右移动n位,左侧补符号位。用途:保留负数的符号,用于有符号数的除法。示例(算术右移1位,假设为有符号数): 1101 (-3的补码) >> 1 = 1110 (-2的补码) 四、运算应用与优化补码的优势:统一加减法运算(减法通过补码转换为加法)。避免原码和反码中的双零问题,简化硬件设计。溢出处理:算术运算可能产生溢出(结果超出位数范围),需通过进位标志位(Carry Flag)或溢出标志位(Overflow Flag)检测。快速乘除法:乘法通过移位和加法优化(如Booth算法)。除法通过试商和减法优化(如恢复余数法或非恢复余数法)。位操作技巧:交换变量值(无需临时变量):a ^= b; b ^= a; a ^= b; 判断奇偶性:if (x & 1) { /* 奇数 */ }取绝对值(补码技巧):int mask = x >> (sizeof(int) * 8 - 1); x = (x + mask) ^ mask;
  • [技术干货] 软考知识点——原码、反码、补码、移码以及他们的关系
    原码、反码、补码和移码是计算机中用于表示数值的编码方式,它们在处理有符号数(正数和负数)时各有特点,尤其在二进制运算中扮演重要角色。以下是它们的详细介绍及相互关系:1. 原码(Sign-Magnitude)定义:原码是最直观的数值表示方法,用最高位表示符号(0为正,1为负),其余位表示数值的绝对值。示例(以8位二进制为例):+5:00000101-5:10000101特点:直观易懂,但存在两个零(+0和-0),且加减法运算复杂(需判断符号位)。适用场景:仅用于理解数值的符号与绝对值关系,实际运算中较少直接使用。2. 反码(Ones’ Complement)定义:反码是对原码的改进,正数的反码与原码相同,负数的反码是对其绝对值的原码按位取反(符号位不变)。示例(8位二进制):+5:00000101(与原码相同)-5:11111010(原码10000101取反后得)特点:解决了原码中加减法运算复杂的问题,但仍存在两个零(00000000和11111111)。适用场景:早期计算机中用于简化运算,现逐渐被补码取代。3. 补码(Two’s Complement)定义:补码是现代计算机中最常用的数值表示方法。正数的补码与原码相同,负数的补码是其反码加1。示例(8位二进制):+5:00000101(与原码、反码相同)-5:原码:10000101反码:11111010补码:11111011(反码加1)特点:唯一零表示:00000000表示+0,10000000在补码中表示-128(8位二进制范围:-128~127),避免了反码中的两个零问题。运算简便:加法、减法可统一为补码加法(如a - b = a + (-b的补码)),简化了硬件设计。适用场景:现代计算机中几乎所有数值运算均采用补码表示。4. 移码(Excess-K)定义:移码主要用于浮点数的阶码部分,通过将数值加上一个固定偏移量K(通常为2^(n-1),n为位数)来表示。示例(8位移码,K=128):实际值0:移码为0 + 128 = 128(二进制10000000)实际值1:移码为1 + 128 = 129(二进制10000001)实际值-1:移码为-1 + 128 = 127(二进制01111111)特点:便于比较:移码的数值大小关系与实际值一致(如10000001 > 10000000对应1 > 0),适合浮点数阶码的排序。无符号数处理:移码将有符号数转换为无符号数范围,简化了硬件比较逻辑。适用场景:浮点数标准(如IEEE 754)中阶码的编码方式。关系总结原码、反码、补码的转换链:正数:三者相同。负数:原码 → 反码(按位取反,符号位不变) → 补码(反码加1)。补码 → 反码(补码减1) → 原码(反码按位取反,符号位不变)。补码与移码的关联:移码可视为补码的符号位取反(以8位为例,补码的符号位为1时,移码对应位为0,反之亦然),但两者用途不同(补码用于数值运算,移码用于阶码比较)。设计目的:原码:直观表示符号与绝对值。反码:简化原码的加减法运算(过渡方案)。补码:彻底解决加减法运算问题,统一硬件设计。移码:优化浮点数阶码的比较与存储。
  • [技术干货] CPU密集型任务
    CPU密集型任务是指在执行过程中,主要时间消耗在CPU的计算操作上,而非等待输入/输出(IO)完成的任务类型。这类任务的核心特点是CPU持续处于高负载状态,性能瓶颈通常在于CPU的算力或并行处理能力。以下是详细解释:核心特征时间消耗分布任务执行时间中,超过50%用于CPU计算(如算术运算、逻辑判断、数据转换等)。IO操作(如磁盘读写、网络传输)占比极低,甚至可以忽略不计。典型场景科学计算:气象模拟、分子动力学、量子化学计算。图像/视频处理:渲染、编码/解码、滤镜应用。机器学习:模型训练、特征提取、矩阵运算(如深度学习中的张量计算)。加密解密:RSA、AES等算法的密钥生成和数据加解密。压缩解压:大规模文件的压缩(如ZIP、RAR)或解压操作。游戏物理引擎:碰撞检测、刚体动力学模拟。性能瓶颈CPU算力:单核频率、核心数量、指令集优化(如AVX-512)。并行效率:多线程/多进程的负载均衡、线程间通信开销。内存带宽:高频计算中,CPU与内存之间的数据传输速度可能成为限制因素。与IO密集型任务的对比特性CPU密集型任务IO密集型任务核心资源消耗CPU计算能力(算术、逻辑、数据转换)磁盘、网络、数据库等IO设备CPU利用率高(持续满负荷运算)低(等待IO时CPU空闲)优化方向提升单核性能、利用多核并行减少IO等待时间、提升并发能力典型语言选择C++、Rust、Fortran(接近硬件层)Java(虚拟线程)、Go、Node.js(异步IO)实际案例深度学习模型训练任务流程:前向传播(矩阵乘法)→ 计算损失 → 反向传播(梯度计算)→ 参数更新。性能瓶颈:GPU/TPU的浮点运算能力(如FP16/FP32精度下的TFLOPS)。优化手段:使用CUDA/OpenCL加速、混合精度训练、分布式并行。视频编码(H.264/H.265)任务流程:帧内预测 → 运动估计 → 变换量化 → 熵编码。性能瓶颈:CPU的SIMD指令集(如AVX2)对宏块处理的效率。优化手段:启用硬件加速(如Intel Quick Sync)、多线程分块处理。密码学哈希计算(SHA-256)任务流程:对输入数据分块 → 迭代压缩函数 → 输出哈希值。性能瓶颈:CPU的位运算能力和流水线效率。优化手段:使用专用指令集(如SHA扩展)、多线程并行计算。优化技术多核并行化多线程:通过std::thread(C++)、java.util.concurrent(Java)或rayon(Rust)实现任务分解。多进程:利用fork()(Unix)或multiprocessing(Python)绕过GIL限制。GPU加速:通过CUDA、OpenCL或Vulkan Compute将计算密集型部分卸载至GPU。算法优化降低复杂度:从O(n²)优化至O(n log n)(如快速排序替代冒泡排序)。近似计算:在允许误差的场景下使用近似算法(如蒙特卡洛模拟)。内存局部性:优化数据结构(如使用连续内存的数组替代链表)减少缓存未命中。指令集优化SIMD指令:利用AVX-512、SSE等指令集并行处理多个数据(如同时计算4个浮点数乘法)。编译器优化:启用-O3(GCC/Clang)或/O2(MSVC)优化标志,自动向量化循环。硬件加速专用芯片:使用FPGA或ASIC加速特定计算(如比特币矿机的SHA-256加速)。异构计算:结合CPU+GPU+DPU(数据处理单元)分工协作。为什么Rust在CPU密集型任务中表现突出?Rust通过以下特性优化CPU密集型任务:零成本抽象:编译期确定内存布局,避免运行时开销(如Java的自动装箱/拆箱)。细粒度控制:可直接操作寄存器、缓存行等硬件资源,优化内存访问模式。无GC停顿:手动内存管理避免垃圾回收导致的计算中断(如Java的Stop-The-World)。并发安全:通过所有权模型消除数据竞争,简化多线程编程。示例:在矩阵乘法中,Rust可通过unsafe代码直接调用SIMD指令,实现比Java高3-5倍的性能;而Java需依赖JVM的自动向量化(如@HotSpotIntrinsicCandidate注解),优化空间有限。为什么JDK21在CPU密集型任务中仍具竞争力?JDK21通过以下特性缩小与Rust的差距:向量API(JEP 338):允许在Java中直接编写SIMD指令,提升数值计算性能。记录类(Records)和密封类:减少对象创建开销,优化数据结构内存布局。ZGC/Shenandoah垃圾回收器:将GC停顿时间控制在毫秒级,减少对计算任务的干扰。虚拟线程:虽主要用于IO密集型任务,但在计算任务中也可通过轻量级线程提升并发度。示例:在金融风险模型(如蒙特卡洛模拟)中,JDK21的向量API可使计算速度接近C++水平,而Rust仍需手动优化才能达到同等性能。
  • [技术干货] IO密集型任务
    IO密集型任务是指在执行过程中,大部分时间消耗在输入/输出(Input/Output)操作上,而非CPU计算的任务类型。这类任务的核心特点是CPU利用率较低,但系统吞吐量受限于IO设备的性能。以下是详细解释:核心特征时间消耗分布任务执行时间中,超过50%用于等待IO完成(如磁盘读写、网络传输、数据库查询等)。CPU在等待IO期间处于空闲状态,导致整体资源利用率不高。典型场景网络通信:Web服务器处理HTTP请求、API网关转发请求、消息队列消费。文件操作:日志写入、文件上传/下载、大数据处理中的数据加载。数据库交互:频繁的SQL查询、事务处理、缓存读写。用户交互:图形界面响应、游戏输入处理、移动端应用网络请求。性能瓶颈IO设备速度:磁盘读写速度(HDD约100-200MB/s,SSD约500MB/s-7GB/s)、网络带宽(如1Gbps网卡理论最大125MB/s)。并发处理能力:单线程下IO操作会阻塞后续任务,需通过多线程/异步IO提升吞吐量。与CPU密集型任务的对比特性IO密集型任务CPU密集型任务核心资源消耗磁盘、网络、数据库等IO设备CPU计算能力(算术运算、逻辑判断等)CPU利用率低(等待IO时CPU空闲)高(持续满负荷运算)优化方向减少IO等待时间、提升并发能力优化算法、利用多核并行计算典型语言选择Java(虚拟线程)、Go、Node.jsC++、Rust、Fortran实际案例Web服务器处理请求每个HTTP请求需要:接收数据(网络IO)→ 查询数据库(磁盘IO)→ 返回响应(网络IO)。若使用同步阻塞模型(如传统Java线程池),高并发下线程会因等待IO而大量堆积,导致性能下降。优化方案:异步非阻塞IO(如JDK21虚拟线程、Node.js事件循环):单线程处理多个IO操作,减少线程切换开销。多线程+连接池:通过线程池复用连接,避免频繁创建/销毁资源。大数据ETL(抽取、转换、加载)任务流程:从数据库读取数据(磁盘IO)→ 清洗转换(少量CPU计算)→ 写入目标存储(磁盘/网络IO)。性能瓶颈:磁盘读写速度远低于CPU处理能力,需通过并行化IO操作(如分片读取)提升效率。实时日志分析系统需持续接收日志(网络IO)→ 解析内容(少量CPU计算)→ 写入存储(磁盘IO)。优化手段:使用Kafka等消息队列缓冲日志,避免IO阻塞导致数据丢失。优化技术异步IO模型通过回调、Promise或协程(如Go的goroutine、Java的虚拟线程)实现非阻塞IO,提升并发能力。缓冲与缓存使用内存缓冲(如BufferedInputStream)减少直接磁盘IO次数。通过Redis等缓存热点数据,降低数据库查询压力。并行化IO将大文件分块读取,或同时从多个数据源获取数据(如并行下载)。选择合适的存储介质对高频访问数据使用SSD替代HDD,或采用内存数据库(如Redis)。为什么JDK21在IO密集型任务中表现突出?JDK21引入的虚拟线程(轻量级线程)通过以下机制优化IO密集型任务:减少线程开销:传统线程模型中,每个连接需占用MB级内存,而虚拟线程仅需KB级。自动调度:JVM在虚拟线程等待IO时自动挂起,并切换至其他就绪线程,充分利用CPU资源。同步开发模式:开发者可用同步代码编写异步逻辑,降低开发复杂度。示例:一个支持10万并发的Web服务,使用JDK21虚拟线程可能仅需数百个操作系统线程,而传统线程池可能需要数万线程,导致内存耗尽和频繁上下文切换。
  • [技术干货] 实时流处理
    实时流处理(Real-time Stream Processing)是一种针对连续、无界、高速流动的数据流进行即时处理和分析的技术架构,其核心目标是在数据产生的瞬间完成处理,并实时反馈结果。与传统的批量处理(Batch Processing)相比,实时流处理更注重低延迟、高吞吐和事件驱动的特性,适用于需要即时响应的场景。一、核心概念与特点数据流特性:无界性:数据持续产生,没有明确的开始或结束(如传感器数据、用户点击流)。高速性:数据以毫秒或秒级速度到达,需快速处理以避免积压。有序性:数据按时间顺序排列,处理时需保持事件的时间语义。处理模式:事件驱动:每个数据事件触发计算逻辑(如用户下单后立即触发风控检查)。状态管理:维护处理过程中的中间状态(如窗口聚合、会话分析)。容错机制:通过检查点(Checkpoint)和状态回滚保障故障恢复。与批量处理的对比:维度实时流处理批量处理数据范围连续数据流有限数据集延迟毫秒/秒级分钟/小时级资源占用持续运行,资源按需扩展任务触发时分配资源典型场景实时监控、风控日志分析、报表生成二、核心技术组件消息队列(Message Queue):作用:缓冲数据流,解耦生产者与消费者,保障数据不丢失。典型工具:Kafka、Pulsar、RabbitMQ。关键特性:高吞吐、持久化存储、分区(Partition)支持并行消费。流处理引擎(Stream Processing Engine):作用:执行实时计算逻辑(如过滤、聚合、关联)。典型工具:Apache Flink:支持有状态计算、精确一次语义(Exactly-once)。Apache Spark Streaming:基于微批处理(Micro-batch),适合近似实时场景。Apache Storm:纯流式处理,低延迟但状态管理较弱。Kafka Streams:轻量级库,适合与Kafka集成的简单处理。状态后端(State Backend):作用:存储处理过程中的中间状态(如窗口计数、用户会话)。类型:内存状态:RocksDB(本地磁盘+内存缓存)。远程状态:HDFS、S3(分布式存储)。时间语义(Time Semantics):事件时间(Event Time):基于数据生成时间处理(如传感器数据的时间戳)。处理时间(Processing Time):基于系统接收数据的时间处理。摄入时间(Ingestion Time):数据进入系统的中间时间。三、典型应用场景实时监控与告警:场景:服务器性能指标(CPU、内存)实时分析,异常时触发告警。技术栈:Kafka收集指标,Flink计算阈值,Prometheus/Alertmanager告警。金融风控:场景:实时检测信用卡欺诈交易(如异地登录、异常金额)。技术栈:Kafka接收交易数据,Flink关联用户历史行为,规则引擎触发拦截。推荐系统:场景:用户实时行为(点击、浏览)触发个性化推荐。技术栈:Flink处理行为流,更新用户画像,Redis存储推荐结果。物联网(IoT):场景:工业设备传感器数据实时分析,预测故障。技术栈:MQTT协议传输数据,Flink计算设备状态,触发维护工单。实时日志分析:场景:应用日志实时聚合,监控错误率或性能瓶颈。技术栈:Fluentd收集日志,Flink统计错误类型,ELK(Elasticsearch+Logstash+Kibana)可视化。四、挑战与解决方案乱序数据(Out-of-Order Events):问题:事件时间晚于处理时间,导致计算结果不准确。解决方案:使用水印(Watermark)机制,等待延迟数据到达后再触发计算。状态管理:问题:长时间运行的任务状态可能过大,影响性能。解决方案:分层状态存储(内存+磁盘)、状态快照(Checkpoint)定期备份。反压(Backpressure):问题:下游处理速度慢于上游数据到达速度,导致队列积压。解决方案:动态调整并行度、使用背压感知的源(如Kafka的max.poll.records)。精确一次语义(Exactly-once):问题:避免重复处理或数据丢失。解决方案:Flink的分布式快照+事务性写入(如Kafka的事务生产者)。五、发展趋势AI与流处理融合:在流中嵌入机器学习模型(如Flink ML),实现实时预测(如欺诈检测)。统一批流处理:工具如Apache Beam提供抽象层,支持同一套代码运行在批/流模式下。Serverless流处理:云厂商(AWS Kinesis、Azure Stream Analytics)提供按需计费的流处理服务,降低运维成本。边缘计算集成:在边缘节点进行初步流处理(如过滤、聚合),减少中心云负载。
  • [技术干货] 存储计算分离架构适用的场景
    存储计算分离架构通过解耦存储与计算资源,实现了弹性扩展、成本优化和性能提升,适用于数据量大、计算需求波动明显或对资源利用率要求高的场景。以下是其核心适用场景及具体分析:一、大数据处理与分析场景描述:需要处理海量结构化或非结构化数据(如日志、传感器数据、用户行为数据),并进行批量分析、ETL(抽取-转换-加载)或数据挖掘。架构优势:存储层:使用分布式文件系统(如HDFS)或对象存储(如AWS S3),支持PB级数据存储,且成本低于本地磁盘。计算层:通过Spark、Flink等框架动态扩展计算资源,按需处理数据,避免资源闲置。典型案例:电商平台的用户行为分析、金融风控模型的训练。二、机器学习与AI训练场景描述:训练大规模深度学习模型(如图像识别、自然语言处理),需频繁读写训练数据集。架构优势:存储层:采用高性能对象存储或分布式文件系统,支持快速数据访问,同时通过数据分块和缓存减少I/O瓶颈。计算层:动态分配GPU/TPU资源,加速模型训练,训练完成后可释放计算资源,降低成本。典型案例:自动驾驶公司的路测数据训练、医疗影像AI模型的迭代。三、实时流处理场景描述:对实时数据流(如物联网设备数据、金融交易数据)进行低延迟处理和分析。架构优势:存储层:使用支持高吞吐、低延迟的存储系统(如Kafka日志存储、Pulsar分片存储),确保数据不丢失。计算层:通过Flink、Storm等流处理引擎动态扩展计算节点,实时处理数据并触发告警或决策。典型案例:智能工厂的设备故障预测、股票交易系统的实时风控。四、数据库与在线服务场景描述:高并发读写场景(如电商订单系统、社交媒体),需兼顾性能与成本。架构优势:存储层:采用共享存储(如PolarDB的PolarStore),支持多计算节点并发访问,避免数据拷贝开销。计算层:根据负载动态增减计算节点(如Serverless模式),应对突发流量(如“双11”大促)。典型案例:阿里巴巴的PolarDB数据库、腾讯云的TDSQL。五、云原生与混合云环境场景描述:企业需在公有云、私有云或本地数据中心间灵活部署应用,同时保持数据一致性。架构优势:存储层:统一存储接口(如S3兼容API),支持跨云数据访问,避免数据迁移成本。计算层:在公有云部署计算资源,利用弹性伸缩能力;私有云保留敏感数据,满足合规要求。典型案例:跨国企业的全球业务分析、金融行业的灾备架构。六、科研与高性能计算(HPC)场景描述:需要大规模并行计算的科研领域(如气候模拟、基因测序)。架构优势:存储层:采用并行文件系统(如Lustre),支持高速数据读写,满足计算节点对数据的并发需求。计算层:通过超级计算机或云HPC集群动态分配计算资源,缩短任务完成时间。典型案例:气象局的气候预测模型、生物医药公司的蛋白质结构分析。七、媒体与内容处理场景描述:处理海量音视频数据(如视频转码、图片渲染),需高吞吐存储和并行计算能力。架构优势:存储层:使用对象存储或分布式文件系统,支持低成本存储和快速检索。计算层:通过GPU集群或无服务器函数(如AWS Lambda)并行处理任务,按使用量计费。典型案例:短视频平台的视频审核、影视制作公司的特效渲染。八、数据仓库与湖仓一体场景描述:构建统一的数据存储与分析平台,支持结构化与非结构化数据混合查询。架构优势:存储层:采用数据湖(如Delta Lake、Iceberg)或湖仓一体架构(如Databricks),支持ACID事务和版本控制。计算层:通过Spark SQL或Presto等引擎动态扩展计算资源,实现交互式分析。典型案例:企业的统一数据平台、零售行业的客户画像分析。九、灾备与长期归档场景描述:需要低成本、高可靠的长期数据存储,同时支持快速恢复。架构优势:存储层:使用冷存储(如AWS Glacier、阿里云OSS低频访问)降低存储成本,通过多副本和跨区域部署保障数据安全。计算层:仅在需要恢复数据时启动计算资源,避免持续成本。典型案例:金融机构的交易记录归档、医疗行业的病历长期保存。十、物联网(IoT)与边缘计算场景描述:处理海量设备产生的时序数据(如传感器读数),需低延迟存储和边缘计算能力。架构优势:存储层:在边缘节点部署轻量级存储(如InfluxDB时序数据库),中心云存储历史数据。计算层:边缘节点进行实时过滤和聚合,中心云进行深度分析,减少数据传输量。典型案例:智慧城市的交通流量监控、工业物联网的设备预测性维护。
  • [技术干货] 存储计算分离架构概述
    存储计算分离架构(Storage-Compute Separation)是一种将数据存储与数据处理/计算功能解耦的数据架构设计理念,其核心是通过独立的存储层和计算层实现高效的数据管理与计算资源分配。以下从定义、架构组成、优势特点、应用场景及发展趋势五个方面展开分析:一、定义与原理存储计算分离架构将传统架构中耦合的存储与计算功能拆分为两个独立模块:存储层:负责数据的持久化存储,采用分布式文件系统(如HDFS)、对象存储(如AWS S3)或关系型数据库等技术,提供数据冗余备份、访问控制等功能。计算层:负责数据处理与分析,支持分布式计算框架(如Hadoop、Spark)或实时计算框架(如Storm、Flink),通过任务调度和资源分配实现高效计算。核心原理:存储层与计算层通过网络进行数据交互,计算节点按需从存储层获取数据,避免传统架构中存储与计算资源绑定导致的扩展性瓶颈。二、架构组成存储层:技术选型:分布式文件系统(HDFS)、对象存储(Ceph、MinIO)、关系型数据库等。功能:数据持久化、冗余备份、访问控制、元数据管理。优势:支持海量数据存储,通过数据分块和副本策略提高可靠性和读写性能。计算层:技术选型:分布式计算框架(Spark、Flink)、实时计算引擎(Storm)、深度学习框架(TensorFlow、PyTorch)。功能:任务调度、资源分配、并行计算、实时分析。优势:灵活扩展计算资源,支持复杂计算任务,如机器学习训练、实时流处理。网络层:技术选型:以太网、InfiniBand、RDMA(远程直接内存访问)。功能:高带宽、低延迟的数据传输,确保存储层与计算层高效协同。三、优势特点弹性扩展:存储与计算资源可独立扩展,满足业务动态需求。例如,数据量增长时仅扩展存储容量,计算高峰期时增加计算节点。资源利用率优化:存储层采用低成本介质(如HDD、对象存储),计算层使用高性能资源(如GPU、SSD),避免资源浪费。性能优化:计算层可通过数据本地化(如Spark的RDD缓存)和并行计算减少数据移动,提升处理效率。实时计算场景中,计算资源可集中部署于高性能节点,满足低延迟需求。成本降低:存储层使用低成本方案,计算层采用按需付费的云资源(如AWS EC2、阿里云ECS),降低TCO(总拥有成本)。高可用性与容灾:存储层通过多副本和跨区域部署实现数据冗余,计算层支持自动容灾切换,提升系统鲁棒性。四、应用场景大数据处理:使用Hadoop/Spark处理海量数据,存储层采用HDFS或对象存储,计算层按需扩展。机器学习与AI:深度学习框架(如TensorFlow)结合分布式存储,支持大规模模型训练和数据预处理。实时分析:流处理框架(如Flink)与低延迟存储协同,实现实时数据洞察(如金融风控、物联网监控)。数据库与消息队列:PolarDB、OceanBase等数据库采用存算分离架构,提升扩展性和成本效益。消息队列(如Pulsar)通过分离Broker(计算)和Bookie(存储)实现灵活扩容。云原生与混合云:存储层保留在本地数据中心,计算资源部署在公有云,兼顾数据安全与计算敏捷性。五、发展趋势硬件创新:专用数据处理器(DPU)、CXL内存池化技术、高性能NVMe SSD等硬件推动架构升级,提升数据密集型应用效率。软件定义存储(SDS):通过软件层抽象存储资源,实现存储与计算的更灵活解耦,支持多云和混合云环境。网存算协同:RDMA、可编程网络设备等技术优化数据传输,减少网络延迟对性能的影响。生态融合:存储计算分离架构与湖仓一体(Data Lakehouse)、Serverless等理念结合,构建统一的数据处理平台。
  • [干货汇总] 鸿蒙应用架构设计:组件化复用与模块化项目案例
    问题背景针对App产品存在多个客户端版本的情况下,同时开发 多 个 App 时,由于业务目标、用户群体可能存在差异,且需兼顾协同效率与质量稳定性,容易暴露出比单一 App 开发更复杂的问题多产品App核心问题,本质是 “个性需求与共性能力的平衡失控”:资源分散导致效率低,协同缺失导致体验乱,版本混乱导致风险高。无 模块化架构设计,项目陷入 “开发慢、改不动、问题多” 的恶性循环。     安卓开发现状人力资源分配矛盾:若 多 个 App 并行开发,核心开发人员(如架构师、资深工程师)需同时跟进多个项目,精力被稀释,导致技术决策延迟、关键问题响应变慢。基层开发人员若按 “1 个 App 对应 1 个团队” 划分,会出现 “同一项基础功能(如图片上传、异常监控)3 个团队各做一套” 的情况,重复劳动率高达 40%-60%,直接拉长整体开发周期。技术栈与规范难统一若 多个 App 由不同团队开发,可能因 “团队习惯” 采用差异技术方案,导致后续跨 App 协作(如人员轮岗、问题排查)成本陡增即使预先制定规范,也可能因 “赶进度” 出现执行偏差(如命名规则、接口格式不统一),后期需额外投入人力做标准化整改共性能力重复开发,维护难度翻倍:多个 App 必然存在共性能力(如登录、支付、网络请求、数据埋点),若未提前抽象复用,会导致:同一功能出现 多套代码,修复一个共性 Bug(如登录接口超时逻辑)需在 3多个 App 中分别修改,漏改概率增加共性能力升级(如支付渠道新增)需 多个团队同步适配,协调成本随 App 数量呈指数级增长版本规划与测试压力陡增多 个 App 的版本迭代节奏可能不同(如 A App 需每月一更,B App 每两周一更,C App 紧急上线),测试资源(如测试设备、自动化脚本)需在 3 个项目间频繁切换,导致测试覆盖率下降,漏测风险升高。若 多 个 App 依赖同一基础组件(如自研的网络库),该组件升级后,需 多个 App 同步完成兼容性测试才能发布,任何一个 App 的测试延迟都会拖慢整体进度。线上问题连锁反应若共性能力(如埋点 SDK)存在隐藏 Bug,可能导致 多个 App 同时出现数据异常,线上故障排查时需 “多线并行定位”,定位时间比单一 App 问题长 2-3 倍。某一个 App 的紧急发布(如修复崩溃 Bug)可能因 “打包环境共享”“配置文件混淆” 影响其他 App 的发布包稳定性(如误打包旧版本代码)。业务与扩展性:差异需求失控多 个 App 的业务差异(如 A App 需社交功能,B App 需电商功能,C App 需工具功能)可能要求对共性能力做 “定制化修改”(如登录模块为 A App 新增 “第三方社交账号登录”,为 B App 新增 “手机号一键登录”),若修改未抽象成可配置逻辑,会导致共性模块逐渐 “臃肿”,最终失去复用价值 鸿蒙解决方案   整体架构设计思路:          备注:一个业务功能,即为一个工程(整个工程下的一个文件夹),编译出后是一个HAR/HSP类型的包。多个HAR/HSP组合打包出的包为HAP包。(HAR、HSP、HAP包区别参考:https://developer.huawei.com/consumer/cn/doc/architecture-guides/tools-v1_2-ts_35-0000002343405565)        在鸿蒙生态中,通过 ArkTS 语言和 ArkUI 框架的原生支持,可以高效实现 "一套工程、多 App 发布" 的架构。具体实现策略:功能模块包模块化设计:可插拔组件化开发。由组件复用提供基础能力,例如:一键加油、爱车服务、无感支付、在线订单、高德、在线商城等业务功能,每个都由HAR/HSP工程创建,实现业务功能与业务无关的网络库、埋点SDK、图片加载等,每个都由HAR/HSP工程创建,实现基础功能。由业务功能HAR/HSP包调用,为业务功能提供基础能力上述业务功能HAR/HSP包,基础功能HAR/HSP包,可自由组合,被HAP工程引入,由HAP工程打包出用户版、商户版、供应商版三个版本工程架构设计,组件复用,实现一套代码库支撑多 App用户版HAP工程打包:创建hapTasks类型的工程(运行出的包为HAP包),将多个需要的多个业务功能包( HAR/HSP工程(文件夹))引入,编码实现用户版的功能。商户版、供应商版也是如此。用户版打包:需为车主提供便捷的车辆养护、维修、紧急救援等服务,引入一键加油、爱车服务、无感支付HAR/HSP,实现相关业务逻辑后,打包成HAP包商户版打包:需帮助维修店/4S店高效管理客户和服务流程,引入在线订单、高德HAR/HSP,实现相关业务逻辑后,打包成HAP包供应商版打包:为配件供应商提供B2B销售渠道和管理工具,引入在线商城、充值相关渠道配置HAR/HSP,实现相关业务逻辑后,打包成HAP包如何打HAP包(多个app的差异化打包):。上述用户版、商户版、供应商版工程,每个工程需要配置:包名、签名、证书、打包输出的文件夹路径、相关资源(如主题资源、图片资源等)每个 HAP 的 module.json 中,bundleName、bundleType、versionCode、debug、minAPIVersion 保持一致;module 的 name 字段互不相同;minCompatibleVersionCode、targetAPIVersion 保持一致配置后,通过执行Hvigor命令,打包成HAP包(Hvigor脚本参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/packing-tool#多工程打包指令)    解决痛点模块化设计,代码复用率提升:基础组件统一维护,避免重复开发(复用率可达 70%-90%)。功能模块通过配置按需加载,无需为每个 App 单独编写代码,并且可以将可插拔的模块组合打包多个App。组件复用,开发效率提升:修改公共组件自动同步到所有 App,减少重复测试和发布流程。新增功能只需在对应模块开发,通过配置快速集成到需要的 App。维护成本降低:单一工程结构减少代码仓库管理复杂度,团队协作更高效。版本控制更简单,所有 App 基于同一代码基线演进。灵活扩展能力:新增 App 只需创建新的配置文件和专属资源,无需复制代码。功能模块可独立升级,不影响其他 App。      组件设计思路:   组件复用,设计思路:基础层组件:网络库、埋点SDK、图片加载等与业务无关联的,放入基础层,可供任何App提供底层能力业务层:支付模块、订单、商品详情等,与业务强关联,需要考虑多个App版本的不同差异化能力、公共能力,进一步抽出例如可选复用的业务功能,作为多个App集成的公共业务差异化的使用动态Feature包由多个App灵活调用,并且可设计多个Feature包,可插拔给多个App组合使用产品层:根据不同App版本,将公共资源统一管理、特定产品特定资源文件、代码中动态加载资源,封装在不同的App中每个App就固定使用这些资源、动态加载业务层的业务包,灵活配置不用App版本之间所需要的业务功能基础层、业务层功能维护: 每个基础能力、业务模块完全独立开发,无需关心是哪个App来调用,仅需关注本身能力、业务的迭代开发 基础组件案例案例1,验证码组件:  import { inputMethod } from '@kit.IMEKit';import { emitter } from '@kit.BasicServicesKit';import { hilog } from '@kit.PerformanceAnalysisKit';@Extend(Text)function verifyCodeUnitStyle() { .fontSize($r("sys.float.ohos_id_text_size_body1")) .fontWeight(60) .textAlign(TextAlign.Center) .width($r("app.integer.verify_code_code_unit_with")) .height('100%') .margin({ left: $r("app.integer.verify_code_code_unit_margin"), right: $r("app.integer.verify_code_code_unit_margin") }) .border({ width: { bottom: $r("app.integer.verify_code_code_border_width") }, color: { bottom: Color.Grey }, style: { bottom: BorderStyle.Solid } })}@Componentstruct VerifyCodeComponentWithoutCursor { @State codeText: string = ""; private readonly verifyID: string = "verifyCodeComponent"; private inputController: inputMethod.InputMethodController = inputMethod.getController(); // 监听键盘弹出收起状态 @State isKeyboardShow: boolean = false; private verifyCodeLength: number = 6; private isListen: boolean = false; private textConfig: inputMethod.TextConfig = { inputAttribute: { textInputType: inputMethod.TextInputType.NUMBER, enterKeyType: inputMethod.EnterKeyType.GO }, }; private codeIndexArray: Array<number> = Array.from([0, 1, 2, 3, 4, 5]); // 注册路由返回函数,案例插件不触发 popRouter: () => void = () => { }; aboutToAppear(): void { // 注册返回监听,包括点击手机返回键返回与侧滑返回 this.listenBackPress(); } async attachAndListen(): Promise<void> { focusControl.requestFocus(this.verifyID); await this.inputController.attach(true, this.textConfig); logger.info("attached"); this.listen(); this.isKeyboardShow = true; } listenBackPress() { let innerEvent: emitter.InnerEvent = { eventId: 5 }; // 收到eventId为5的事件后执行回调函数 emitter.on(innerEvent, () => { if (this.isKeyboardShow) { // 退出文本编辑状态 this.inputController.hideTextInput(); this.isKeyboardShow = false; } else { this.popRouter(); } }); } aboutToDisappear(): void { this.off(); // 关闭事件监听 emitter.off(5); } /** * TODO 知识点:绑定输入法 */ async attach() { await this.inputController.attach(true, this.textConfig); logger.info("attached"); } /** * TODO:知识点:解绑 */ off(): void { this.inputController.off("insertText"); this.inputController.off("deleteLeft"); this.isListen = false; logger.info("detached"); // 退出文本编辑状态 this.inputController.hideTextInput(); this.isKeyboardShow = false; } /** * TODO 知识点:订阅输入法代插入、向左删除事件,从而获得键盘输入内容 */ listen() { if (this.isListen) { return; } this.inputController.on("insertText", (text: string) => { if (this.codeText.length >= this.verifyCodeLength || isNaN(Number(text)) || text === ' ') { return; } this.codeText += text; if (this.codeText.length === this.verifyCodeLength) { logger.info("VerifyCode: %{public}s", this.codeText); } logger.info("VerifyCode [insert]: %{public}s", this.codeText); }) this.inputController.on("deleteLeft", (length: number) => { this.codeText = this.codeText.substring(0, this.codeText.length - 1); logger.info("VerifyCode [delete left]: %{public}s", this.codeText); }) this.isListen = true; logger.info("listener added"); } /** * TODO 知识点:部分验证码场景要完全禁止对输入验证码的选中、复制等功能,因此可以使用Text组件完成 */ @Builder buildVerifyCodeComponent() { Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) { ForEach(this.codeIndexArray, (item: number, index: number) => { Text(this.codeText[item]) .verifyCodeUnitStyle() }, (item: number, index: number) => item.toString()) } .id(this.verifyID) /** * TODO:知识点:当可视面积变化时进行绑定注册与解绑 */ .onBlur(() => { this.off(); }) .backgroundColor(Color.Transparent) .height($r("app.integer.verify_code_verify_code_height")) .margin({ left: $r("sys.float.ohos_id_card_margin_start"), right: $r("sys.float.ohos_id_card_margin_start") }) .defaultFocus(true) .onClick(() => { // TODO 知识点:点击本组件时弹出输入法,因为这里使用的是Text组件,因此需要重新attach,而不能直接使用showSoftKeyboard this.attachAndListen(); }) } build() { Row() { this.buildVerifyCodeComponent() } }}@Builderexport function VerifyCodeViewBuilder() { VerifyCodeView()}/** * 验证码组件:禁用选中、复制、光标 */@Componentexport struct VerifyCodeView { popRouter: () => void = () => { }; build() { NavDestination(){ Column() { VerifyCodeComponentWithoutCursor({ popRouter: this.popRouter }) } .height('100%') .width('100%') .justifyContent(FlexAlign.Center) } .title('验证码界面') }}/** * 日志打印类 */class Logger { private domain: number; private prefix: string; private format: string = '%{public}s, %{public}s'; constructor(prefix: string) { this.prefix = prefix; this.domain = 0xFF00; this.format.toUpperCase(); } debug(...args: string[]) { hilog.debug(this.domain, this.prefix, this.format, args); } info(...args: string[]) { hilog.info(this.domain, this.prefix, this.format, args); } warn(...args: string[]) { hilog.warn(this.domain, this.prefix, this.format, args); } error(...args: string[]) { hilog.error(this.domain, this.prefix, this.format, args); }}export let logger = new Logger('[CommonAppDevelopment]') 案例2,地址选择器组件: import { window } from '@kit.ArkUI';import { AddressInfo, AddressType, CommonAddressList, Location, Province } from '../model/AddressModel';import { JsonUtils } from '../utils/JsonUtils';/** * 常量 */export default class Constants { // 自定义TabBar切换tab动画分隔线宽度 public static readonly DIVIDER_WIDTH: number = 20; // 顶部省市区间隔 public static readonly AREA_SPACE: number = 12; // rawfile目录下的省市区json文件 public static readonly JSON_FILE: string = 'address';}/** * 自定义地址选择组件CustomAddressPicker */@Componentexport struct CustomAddressPicker { // 底部导航条区域高度 @State bottomHeight: number = 0; // 选择的省市区 @State provinceCityRegion: string = '省、市、区'; // 用于对外提供选择后的省市区信息或者传入地址信息 @Link address: AddressInfo; // 地址选择半模态弹窗显隐标志位 @State isShow: boolean = false; // 当前选择的省、市、区tab页签的index。0表示省,1表示市,2表示区 @State currentIndex: number = AddressType.Province; // 调用changeIndex切换TabContent动画时长 @State animationDuration: number = 300; // 省List @State provinceList: CommonAddressList[] = []; // 市List @State cityList: CommonAddressList[] = []; // 区List @State regionList: CommonAddressList[] = []; // 记录上一次市List @State lastCityList: CommonAddressList[] = []; // 记录上一次区List @State lastRegionList: CommonAddressList[] = []; // 存放选择的省数据 @State province: Province = new Province('', '', []); // 记录当前省市区选择信息 @State currentSelectInfo: AddressInfo = new AddressInfo(); // 记录上一次省市区选择信息 @State lastSelectInfo: AddressInfo = new AddressInfo(); // 选择的省市区名下方的下滑线水平偏移量 @State leftMargin: number = 0; // 存放上一次选择的省市区名下方的下滑线水平偏移量 private lastLeftMargin: number = 0; // 存放选择的省市区名下方的下滑线位置信息 private textInfos: [number, number][] = []; // 存放从json读取的省市区数据 private data: Province[] = []; private controller: TabsController = new TabsController(); async aboutToAppear() { // 获取导航条高度,半模态弹窗内容进行避让 window.getLastWindow(getContext(), (err, data) => { const avoidAreaBottom = data.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) this.bottomHeight = avoidAreaBottom.bottomRect.height }) // 从json文件读取省市区数据 const addressData: Province[] = await JsonUtils.getAddressJson(Constants.JSON_FILE) if (!addressData || addressData.length === 0) { console.error('省市区数据加载失败'); return; } for (let index = 0; index < addressData.length; index++) { this.data.push(addressData[index]) this.provinceList.push(new CommonAddressList(addressData[index].code, addressData[index].name)); } // 首次加载AddressPickerComponent如果传入了有效的地址信息,拉起地址选择半模态页面时,会按传入的地址信息进行显示 this.initAddressSelect() } /** * 首次加载AddressPickerComponent如果传入了有效的地址信息时,在拉起地址选择半模态页面时,会按传入的地址信息进行显示 */ initAddressSelect() { if (this.address.province !== '' && this.address.city !== '' && this.address.region !== '') { this.provinceCityRegion = this.address.province + this.address.city + this.address.region this.currentSelectInfo.province = this.address.province this.currentSelectInfo.city = this.address.city this.currentSelectInfo.region = this.address.region //查找对应的市,区地址信息 this.data.forEach(province => { if (province.name === this.address.province) { this.currentSelectInfo.provinceId = province.code; this.address.provinceId = province.code; province.children.forEach(city => { // 只提取市级的code和name this.cityList.push(new CommonAddressList(city.code, city.name)) if (city.name === this.address.city) { this.currentSelectInfo.cityId = city.code this.address.cityId = city.code city.children.forEach(region => { // 只提取区级的code和name this.regionList.push(new CommonAddressList(region.code, region.name)) if (region.name === this.address.region) { this.currentSelectInfo.regionId = region.code this.address.regionId = region.code // 深拷贝保存到相应的变量中 this.lastSelectInfo = JSON.parse(JSON.stringify(this.currentSelectInfo)) this.lastCityList = JSON.parse(JSON.stringify(this.cityList)); this.lastRegionList = JSON.parse(JSON.stringify(this.regionList)); this.animationDuration = 0; } }) } }) } }) } } /** * 选择的省市区名下方的下滑线动画 * @param duration 动画时长 * @param leftMargin 下划线动画偏移量 */ startAnimateTo(duration: number, leftMargin: number) { animateTo({ duration: duration, // 动画时长 curve: Curve.Linear, // 动画曲线 iterations: 1, // 播放次数 playMode: PlayMode.Normal // 动画模式 }, () => { this.leftMargin = leftMargin; }) } /** * 用于显示选择的省、市、区名 * @param params 传入要显示的省、市、区名 */ @Builder locationItem(params: Location) { Text(params.name === '' ? "请选择" : params.name) .height("100%") .fontSize(16) .fontWeight(this.currentIndex === params.index ? 500 : 400) .fontColor(this.currentIndex === params.index ? "#cc000000" : "#ff8d8d8d") .constraintSize({ maxWidth: "33%" }) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(1) .margin({ right: 12 }) .onClick(() => { this.controller.changeIndex(params.index) }) .id(params.index.toString()) .onAreaChange((oldValue: Area, newValue: Area) => { //使用组件区域变化回调onAreaChange获取选择的省市区Text组件宽度,存入textInfos数组,用于后续计算选择省市区名后下方下滑线动画水平偏移量leftMargin // 组件区域变化时获取当前Text的宽度newValue.width和x轴相对位置newValue.position.x this.textInfos[params.index] = [newValue.position.x as number, newValue.width as number]; if (this.currentIndex === params.index && params.index === AddressType.Province) { // 计算选择的省市区名下方的下滑线偏移量 this.leftMargin = (this.textInfos[this.currentIndex][1] - 20) / 2 } }) } @Builder customTabs() { Tabs({ controller: this.controller }) { // 省列表 TabContent() { List() { ForEach(this.provinceList, (item: CommonAddressList) => { ListItem() { this.areaNameItem(AddressType.Province, item) } .onClick(() => { // 如果当前点击选择的省与之前选择一样,跳过省、市数据获取,直接调用changeIndex(AddressType.City)切换到市列表,减少冗余查询以提升性能 if (this.currentSelectInfo.province == item.name) { this.controller.changeIndex(AddressType.City) return } else { // 重置市和区数据 this.currentSelectInfo.cityId = ''; this.currentSelectInfo.city = ''; this.currentSelectInfo.regionId = ''; this.currentSelectInfo.region = ''; } this.cityList = [] this.regionList = [] this.data.forEach(province => { if (province.name === item.name) { this.province = JSON.parse(JSON.stringify(province)); province.children.forEach(city => { this.cityList.push(new CommonAddressList(city.code, city.name)); }) } }) this.currentSelectInfo.provinceId = item.code; this.currentSelectInfo.province = item.name; this.controller.changeIndex(AddressType.City) }) }, (item: CommonAddressList) => JSON.stringify(item)) } .width("100%") .height("100%") .scrollBar(BarState.Off) .friction(0.6) // 设置摩擦系数 .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring .listDirection(Axis.Vertical) // 排列方向 } // 市列表 TabContent() { List() { ForEach(this.cityList, (item: CommonAddressList) => { ListItem() { this.areaNameItem(AddressType.Province, item) } .onClick(() => { // 如果点击的市和上一次点击的市一样,则不用刷新,减少冗余操作以提升性能 if (this.currentSelectInfo.city === item.name) { this.controller.changeIndex(AddressType.Region) return } else { //重置数据 this.currentSelectInfo.region = '' this.currentSelectInfo.regionId = '' } this.regionList = [] // 点击市,获取该市所有区,存入regionList this.province.children.forEach(city => { if (city.name === item.name) { city.children.forEach(region => { this.regionList.push(new CommonAddressList(region.code, region.name)) }) } }) this.currentSelectInfo.cityId = item.code this.currentSelectInfo.city = item.name this.controller.changeIndex(AddressType.Region) }) }, (item: CommonAddressList) => JSON.stringify(item)) } .width("100%") .height("100%") .scrollBar(BarState.Off) .friction(0.6) .edgeEffect(EdgeEffect.Spring) .listDirection(Axis.Vertical) } // 区列表 TabContent() { List() { ForEach(this.regionList, (item: CommonAddressList) => { ListItem() { this.areaNameItem(AddressType.Province, item) } .onClick(() => { // 记录选择的区信息 this.currentSelectInfo.regionId = item.code; this.currentSelectInfo.region = item.name; this.provinceCityRegion = this.currentSelectInfo.province + this.currentSelectInfo.city + this.currentSelectInfo.region //退出半模态 this.isShow = false // 将当前选中省市区信息保存到lastSelectInfo this.lastSelectInfo.provinceId = this.currentSelectInfo.provinceId; this.lastSelectInfo.province = this.currentSelectInfo.province; this.lastSelectInfo.cityId = this.currentSelectInfo.cityId; this.lastSelectInfo.city = this.currentSelectInfo.city; this.lastSelectInfo.regionId = this.currentSelectInfo.regionId; this.lastSelectInfo.region = this.currentSelectInfo.region; // 在选择完区名后,使用JSON.parse(JSON.stringify(xxx))深拷贝选择的省市区数据,用于后续操作中需要加载上一次选择的完整省市区数据 // 深拷贝保存到相应的变量中 this.lastCityList = JSON.parse(JSON.stringify(this.cityList)); this.lastRegionList = JSON.parse(JSON.stringify(this.regionList)); this.address = JSON.parse(JSON.stringify(this.lastSelectInfo)); }) }, (item: CommonAddressList) => JSON.stringify(item)) } .width("100%") .height("100%") .scrollBar(BarState.Off) .friction(0.6) .edgeEffect(EdgeEffect.Spring) .listDirection(Axis.Vertical) } } .onAppear(() => { if (this.lastSelectInfo.region !== '') { // 上一次选择如果选择到区,再次打开半模态弹窗页面时会显示到区的TabContent this.currentIndex = AddressType.Region; if (this.cityList.length === 0 && this.regionList.length === 0) { // 在已经选择过省市区后,再次打开地址选择半模态弹窗页面,但是没有选择到区就关闭了半模态页面,此时如果再次打开半模态页面,需要显示之前完整选择的省区市数据 this.currentSelectInfo.provinceId = this.lastSelectInfo.provinceId; this.currentSelectInfo.cityId = this.lastSelectInfo.cityId; this.currentSelectInfo.regionId = this.lastSelectInfo.regionId; this.currentSelectInfo.province = this.lastSelectInfo.province; this.currentSelectInfo.city = this.lastSelectInfo.city; this.currentSelectInfo.region = this.lastSelectInfo.region; this.cityList = JSON.parse(JSON.stringify(this.lastCityList)); this.regionList = JSON.parse(JSON.stringify(this.lastRegionList)); this.leftMargin = this.lastLeftMargin; } else { this.leftMargin = this.textInfos[0][1] + this.textInfos[1][1] + (this.textInfos[2][1] - 20) / 2 + 12 * 2 this.lastLeftMargin = this.leftMargin; } this.controller.changeIndex(AddressType.Region) } this.animationDuration = 300 }) .onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => { if (index === targetIndex) { return; } this.currentIndex = targetIndex; let leftMargin: number = 0; let isAnimating: boolean = false; if (index === AddressType.Province && targetIndex === AddressType.City) { // 从省切到市时,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = this.textInfos[0][1] + (this.textInfos[1][1] - Constants.DIVIDER_WIDTH) / 2 + Constants.AREA_SPACE; isAnimating = this.currentSelectInfo.city === '' ? false : true; } else if (index === AddressType.City && targetIndex === AddressType.Region) { // 从市切到区,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = this.textInfos[0][1] + this.textInfos[1][1] + (this.textInfos[2][1] - Constants.DIVIDER_WIDTH) / 2 + Constants.AREA_SPACE * 2; isAnimating = this.currentSelectInfo.region === '' ? false : true; } else if (index === AddressType.City && targetIndex === AddressType.Province) { // 从市切到省,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = (this.textInfos[0][1] - Constants.DIVIDER_WIDTH) / 2; isAnimating = this.currentSelectInfo.city === '' ? false : true; } else if (index === AddressType.Region && targetIndex === AddressType.City) { // 从区切到市,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = this.textInfos[0][1] + (this.textInfos[1][1] - Constants.DIVIDER_WIDTH) / 2 + Constants.AREA_SPACE; isAnimating = this.currentSelectInfo.region === '' ? false : true; } else if (index === AddressType.Region && targetIndex === AddressType.Province) { // 点击自定义TabBar从区切到省,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = (this.textInfos[0][1] - Constants.DIVIDER_WIDTH) / 2; isAnimating = this.currentSelectInfo.region === '' ? false : true; } else if (index === AddressType.Province && targetIndex === AddressType.Region) { // 点击自定义TabBar从省切到区,重新计算选择的省市区名下方的下滑线偏移量 leftMargin = this.textInfos[0][1] + this.textInfos[1][1] + (this.textInfos[2][1] - Constants.DIVIDER_WIDTH) / 2 + Constants.AREA_SPACE * 2; isAnimating = this.currentSelectInfo.region === '' ? false : true; } // 只有在已经选择过的TabContent之间切换时,才会做下划线水平偏移动画 if (isAnimating) { this.startAnimateTo(this.animationDuration, leftMargin); } else { this.leftMargin = leftMargin; } }) .width("100%") .barHeight(0) .layoutWeight(1) } /** * 自定义省/市/区名项 * @param addressType 省/市/区类型 * @param item 省、市、区地址项 */ @Builder areaNameItem(addressType: AddressType, item: CommonAddressList) { Column() { Text(item.name) .width("90%") .height(48) .fontSize(16) .fontColor(this.getFontColor(addressType, item)) Divider().width("90%") .strokeWidth(1) .color("#F1F3F5") } .width("100%") } /** * 获取省、市、区名需要显示的字体颜色 * @param addressType 省/市/区类型 * @param item 省、市、区地址项 * @returns 需要显示的字体颜色 */ getFontColor(addressType: AddressType, item: CommonAddressList): Color | string | Resource { // 省/市/区名字体颜色 let isSelect: boolean = false; if (addressType === AddressType.Province) { isSelect = this.currentSelectInfo.province !== '' && item.name === this.currentSelectInfo.province; } else if (addressType === AddressType.City) { isSelect = this.currentSelectInfo.city !== '' && item.name === this.currentSelectInfo.city; } else if (addressType === AddressType.Region) { isSelect = this.currentSelectInfo.region !== '' && item.name === this.currentSelectInfo.region; } const color = isSelect ? "#fffcb850" : Color.Black; return color; } /** * 地址选择半模态弹窗页面 */ @Builder addressSelectPage() { Column() { this.customTabBar() Divider().width("90%") .strokeWidth(1) .color("#F1F3F5") this.customTabs() } .width("100%") .height("100%") .backgroundColor(Color.White) .padding({ bottom: this.bottomHeight + 'px' }) } /** * 自定义TabBar */ @Builder customTabBar() { RelativeContainer() { Row() { //选择的省名 this.locationItem({ index: AddressType.Province, name: this.currentSelectInfo.province }) // 选择的市名 this.locationItem({ index: AddressType.City, name: this.currentSelectInfo.city }) // 选择的区名 this.locationItem({ index: AddressType.Region, name: this.currentSelectInfo.region }) } .width("85%") .height("80%") .alignRules({ center: { anchor: '__container__', align: VerticalAlign.Center } }) .margin({ bottom: 10 }) .padding({ left: 20, top: 15 }); // 选择的省市区名下方的下滑线 Row() { Divider() .width(20) .strokeWidth(2) .color("#fffcb850") .margin({ left: this.leftMargin }) } .alignItems(VerticalAlign.Top) .width("85%") .height("20%") .alignRules({ bottom: { anchor: '__container__', align: VerticalAlign.Bottom } }) .padding({ left: 20 }) Row() { Image($r("app.media.address_picker_close")) .objectFit(ImageFit.Contain) .width(14) .height(14) .margin({ left: 20 }); } .height("100%") .width("15%") .alignRules({ right: { anchor: '__container__', align: HorizontalAlign.End } }) .onClick(() => { //关闭半模态 this.isShow = false; }); } .width("100%") .height(48) } build() { Column() { Row() { Text("所在地区") .fontSize(16) .fontWeight(500) .margin({ right: 20 }) Text(this.provinceCityRegion) .fontSize(15) .fontColor(this.provinceCityRegion === '省、市、区' ? "#ffacacac" : Color.Black) .fontWeight(300) .constraintSize({ maxWidth: "68%" }) .textOverflow({ overflow: TextOverflow.Ellipsis }) .maxLines(1) } .width("100%") .height(100) .onClick(() => { this.isShow = true this.currentIndex = AddressType.Province }) .bindSheet($$this.isShow, this.addressSelectPage(), { height: "70%", showClose: false, // 设置不显示自带的关闭图标 dragBar: false, onDisappear: () => { this.animationDuration = 0; if (this.currentSelectInfo.region === '') { // 重置所有状态 this.currentSelectInfo.provinceId = ''; this.currentSelectInfo.cityId = ''; this.currentSelectInfo.regionId = ''; this.currentSelectInfo.province = ''; this.currentSelectInfo.city = ''; this.currentSelectInfo.region = ''; this.cityList = []; this.regionList = []; } } }) } .width("100%") .height(54) .padding(2) }}核心能力:组件复用   总结鸿蒙一多开发统一工程与模块化架构,解决人力资源分配矛盾与重复劳动问题。依托标准化组件复用,确保共性能力集中维护,解决功能重复开发、维护难的问题。组件化与配置化打包让测试聚焦差异点,缓解版本规划压力与测试资源冲突。统一资源管理与编译脚本精准控制打包,降低线上问题连锁反应概率,保障多 App 发布稳定性。
  • [技术干货] 弱引用的作用
    弱引用在计算机程序设计中具有多种用途,主要体现在以下几个方面:1. 解决内存泄漏问题弱引用是一种用于解决内存泄漏问题的机制。在程序中,如果一个对象只被强引用所引用,那么即使在程序中不再需要该对象时,由于存在强引用,垃圾回收器无法回收该对象,从而导致内存资源无法释放,造成内存泄漏。而使用弱引用引用该对象时,即使只有弱引用引用该对象,垃圾回收器仍然可以自由地回收该对象,从而避免内存泄漏的发生。2. 缓存应用弱引用在缓存应用中非常有用。当需要缓存对象但不希望这些对象因为被缓存而始终被保持时,可以使用弱引用。这样,当垃圾回收器运行时,如果应用程序的内存占用量高到一定程度,那些不再被其他对象所引用的缓存对象就会被自动释放,从而节省内存资源。3. 监听器模式在监听器模式中,当一个对象需要监听另一个对象的状态变化时,可以使用弱引用来实现。这样,在被监听对象被垃圾回收时,监听器对象也可以自动被释放,从而避免因为监听器对象持有对被监听对象的强引用而导致内存泄漏。4. 对象关系映射(ORM)在对象关系映射(ORM)框架中,为了避免循环引用和内存泄漏,通常会使用弱引用来处理对象之间的关系。例如,一个父对象包含对子对象的引用,而子对象也包含对父对象的引用。为了防止循环引用导致无法释放内存,可以使用弱引用来保存对父对象的引用。5. 临时引用在某些情况下,需要在程序中暂时引用一个对象,但又不希望该引用影响到垃圾回收的行为。此时,可以使用弱引用来实现。这样,在没有其他强引用的情况下,对象可以被垃圾回收器回收。6. 跨语言支持一些配有垃圾回收机制的语言,如Java、C#、Python等,都在不同程度上支持弱引用。这使得开发者可以在这些语言中利用弱引用的特性来优化内存管理。综上所述,弱引用在计算机程序设计中具有多种用途,包括解决内存泄漏问题、缓存应用、监听器模式、对象关系映射、临时引用以及跨语言支持等。这些用途使得弱引用成为了一种重要的内存管理机制。
  • [问题求助] 异步和开线程+同步的方式有啥区别?为啥现在流行异步操作?
    异步和开线程+同步的方式有啥区别?为啥现在流行异步操作?
  • [认证交流] 华为开发者认证E级云架构学习分享
    很高兴成为本次HCCDE云架构培训学习的一员,并且是首批参加的学生。本次课程是结合业界领先架构理论,总结华为云大型复杂项目成功经验,覆盖从项目入手到架构设计完成的完整过程。通过这几天的学习,老师从大型项目的顶层设计、应用解构、微服务、大数据等方面,结合专业的理论知识、丰富的讲解加上有趣的案例,让我对知识点有了更深的理解。除了相关的理论知识,课程还配套了对应场景的动手实验,通过实操,让我首次接触到了很多项目涉及到的华为云高阶产品、组件等。我将会把本次培训学习到的知识运用到未来的工作中,感谢老师们的辛苦指导!希望有兴趣的同学积极报名参加本门课程,一定会让你学有所获!
  • [公告] 【获奖公示】DTSE Tech Talk丨NO.63:边云协同新场景,KubeEdge架构设计与边缘AI实践探索
    中奖结果公示感谢各位小伙伴参与本次活动,欢迎关注华为云DTSE Tech Talk 技术直播更多活动~本次活动获奖名单如下(部分视频号抽奖用户无账号名):账号名 奖项名称 奖品名称 linghz666 口令抽奖 华为云定制T恤hw_008618020934589_01 口令抽奖 华为云定制T恤xj120141121 优质提问  华为云定制双肩包视频号抽奖 华为云定制Polo衫视频号抽奖 华为云定制Polo衫视频号抽奖 华为云定制Polo衫
  • [公告] 【获奖公示】12.6号直播 / DTSE Tech Talk丨NO.50:从架构设计到开发实战,深入浅出了解Sermant
    中奖结果公示感谢各位小伙伴参与本次活动,欢迎关注华为云DTSE Tech Talk 技术直播更多活动~本次活动获奖名单如下:账号名 奖项名称 奖品名称linghz666 优质提问 开发者定制长袖卫衣3XL码hw81541353 优质提问开发者定制长袖卫衣M码hw081993541 优质提问开发者定制长袖卫衣XL码hw076786082 微信抽奖大狮黄色PVC包hid_lm9fpkibkdd6hvh 微信抽奖大狮黄色PVC包xj120141121 官网抽奖开发者定制Polo衫黑色M码qingqingjiayuan6 官网抽奖开发者定制Polo衫黑色xiaozhongy 官网抽奖文件收纳袋yeats_liao 论坛提问奖书籍《微服务架构设计模式》
  • [热门活动] 【云原生专题直播有奖提问】DTSE Tech Talk 技术直播 NO.50:看直播提问题赢华为云定制长袖卫衣、《微服务架构设计模式》书籍等好礼!
    中奖结果公示感谢各位小伙伴参与本次活动,本次活动获奖名单如下:请获奖的伙伴在12月12日之前点击此处填写收货地址,如逾期未填写视为弃奖。再次感谢各位小伙伴参与本次活动,欢迎关注华为云DTSE Tech Talk 技术直播更多活动~直播简介【直播主题】从架构设计到开发实战,深入浅出了解Sermant【直播时间】2023年12月6日 16:30-18:00【直播专家】栾文飞 华为云云原生DTSE技术布道师【直播简介】云原生无代理服务网格太深奥?带你深入浅出了解Sermant,从架构设计到开发实战,步步为营。本期直播将聚焦于Sermant的架构解析及开发实战中,从开发者视角来看核心设计中的插件机制和类加载器架构,在实战中从基础能力开发,到进阶使用统一动态配置能力、统一日志能力等一步步完成插件开发。直播链接:cid:link_1活动介绍【互动方式】直播前您可以在本帖留下您疑惑的问题,专家会在直播时为您解答。直播后您可以继续在本帖留言,与专家互动交流。我们会在全部活动结束后对参与互动的用户进行评选。【活动时间】即日起—2023年12月7日【奖励说明】评奖规则:活动1:直播期间在直播间提出与直播内容相关的问题,对专家评选为优质问题的开发者进行奖励。奖品:华为云定制长袖卫衣活动2:在本帖提出与直播内容相关的问题,由专家在所有互动贴中选出最优问题贴的开发者进行奖励。奖品:书籍《微服务架构设计模式》更多直播活动直播互动有礼:官网直播间发口令“华为云 DTSE”抽华为云定制钢笔礼盒、填写问卷抽华为云定制鼠标等好礼【注意事项】1、所有参与活动的问题,如发现为复用他人内容或直播间中重复内容,则取消获奖资格。2、为保证您顺利领取活动奖品,请您在活动公示奖项后2个工作日内私信提前填写奖品收货信息,如您没有填写,视为自动放弃奖励。3、活动奖项公示时间截止2023年12月8日,如未反馈邮寄信息视为弃奖。本次活动奖品将于奖项公示后30个工作日内统一发出,请您耐心等待。4、活动期间同类子活动每个ID(同一姓名/电话/收货地址)只能获奖一次,若重复则中奖资格顺延至下一位合格开发者,仅一次顺延。5、如活动奖品出现没有库存的情况,华为云工作人员将会替换等价值的奖品,获奖者不同意此规则视为放弃奖品。6、其他事宜请参考【华为云社区常规活动规则】。
  • [综合] 构建高可扩展性的分布式系统
    标题:构建高可扩展性的分布式系统正文: 大家好!今天我想和大家分享一些关于构建高可扩展性的分布式系统的经验和技巧。随着互联网应用的不断发展,我们面临着越来越多的挑战,其中之一就是如何构建能够应对高并发和大规模用户访问的系统。分布式系统正是解决这个问题的有效方式之一。构建高可扩展性的分布式系统需要我们考虑多个方面,下面是一些关键的步骤和策略:选择适当的架构:选择合适的架构对于分布式系统的成功至关重要。常见的架构模式包括微服务架构、事件驱动架构和基于消息的架构。根据应用的需求和复杂性,选择最适合的架构模式。水平扩展:水平扩展是实现高可扩展性的关键。将系统划分为多个可独立部署和扩展的组件,通过增加服务器节点来增加系统的处理能力。使用负载均衡器来分发请求,确保每个组件都能得到平均的负载。异步通信:在分布式系统中,异步通信是提高系统性能和可伸缩性的重要手段。使用消息队列和事件总线来解耦系统的各个组件,提高系统的弹性和可靠性。优化数据存储:选择合适的数据存储方案是构建高可扩展性分布式系统的关键。使用分布式数据库或者分片数据库来分散数据负载。使用缓存技术减轻数据库的压力。监控和容错:在分布式系统中,监控和容错是至关重要的。使用监控工具和日志系统实时跟踪系统的性能和状态。实施故障转移和自动恢复机制来处理节点故障。自动化部署和扩展:利用自动化工具和脚本来简化系统的部署和扩展过程。通过自动化流程,实现快速部署新的节点和组件,提高开发和运维效率。测试和模拟:在构建高可扩展性的分布式系统时,测试和模拟是不可或缺的步骤。使用模拟工具和负载测试工具来评估系统的性能和可扩展性,发现潜在的瓶颈并进行优化。