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

BladeDISC++:Dynamic Shape AI 编译器下的显存优化技术

近年来,随着深度学习技术的迅猛发展,越来越多的模型展现出动态特性,这引发了对动态形状深度学习编译器(Dynamic Shape AI Compiler)的广泛关注。本文将介绍阿里云 PAI 团队近期发布的 BladeDISC++项目,探讨在动态场景下如何优化深度学习训练任务的显存峰值,主要内容包括以下三个部分:

  • Dynamic Shape 场景下显存优化的背景与挑战

  • BladeDISC++的创新解决方案

  • Llama2 模型的实验数据分析

本文内容来自NeurIPS WorkShop 2024 论文:BladeDISC++: Memory Optimizations Based On Symbolic Shape

一、背景与挑战

动态形状深度学习编译器的挑战

随着模型架构的不断演进,其动态性日益增强。例如,传统的计算机视觉(CV)模型中,图像尺寸和批量大小(batch size)在训练过程中会不断变化;大型语言模型的序列长度和批量大小也呈动态调整状态;多模态模型中的图像、视频长度及序列长度同样变化不定。此外,一些更为复杂的混合专家(MoE)模型还涉及与数据相关的动态形状,这些都体现了模型的动态特性。

相应地,Dynamic Shape AI 编译器的发展也在加速。目前一些最先进的编译器,如TVM,OpenXLA主要侧重于静态形状下的优化,包括高效代码生成和图层优化等,类似 Torch Inductor 已经在 Dynamic Shape 场景做了一些工作,但在内存优化方面仍存在不足。其主要挑战有:

1. 张量(Tensor)形状的不确定性

Tensor 形状的动态变化给代码生成带来了麻烦,由于无法在编译期提前买预知 Tensor 的大小和布局,编译器必须采取一些措施使得不同形状下都可以生成高效的代码。

2. 显存分配的动态性

在静态形状下,可以通过整体图计算提前确定显存分配,预先分配适当大小的显存块,并在使用缓存分配器时尽量减少显存碎片。然而,在动态形状下,无法提前预分配显存块的大小,这将导致显存碎片的增加。

3. 优化算法的复杂度增加

常用的图优化算法,比如算子调度,算子融合等需要根据具体的 Tensor 形状来预估内存用量从而对调度、计算策略进行调整。例如,判断两个相似算子是否能融合通常依赖相同的形状信息或相同的代码生成策略,若缺乏形状信息,难以判断融合的可能性,导致性能下降。

针对这些挑战,PAI 团队提出了 BladeDISC++方案,旨在动态形状的工作负载下,尽量将显存峰值控制在某一个阈值之下,使深度学习训练任务可以用更少的显存资源处理更多的训练数据。

总结:随着深度学习模型动态性的增强,动态形状 AI 编译器的重要性日益凸显。然而,这也带来了形状不确定性、优化算法复杂度增加以及显存分配动态性等多重挑战。BladeDISC++通过专注于优化显存峰值,力求在动态形状环境中提供高效的性能表现。

BladeDISC with TorchAcc

Figure1: BladeDISC with TorchAcc

BladeDISC[1] 这一名称来源于Dynamic Shape Compiler,它是一个基于MLIR构建的端到端编译器。由于 BladeDISC 主要作为编译器的后端,前端则支持多种Tracing系统。TorchAcc[2]作为 PyTorch 加速器对大规模深度学习模型训练推理提供了完整的优化方案。在本次实验中,BladeDISC++ 作为 TorchAcc 编译器的后端,对 LLM 训练效率优化进行了完整的验证。

整体架构来看,TorchAcc 的前端支持更多类型的模型,通过 GraphCapture 技术(包括 PyTorch Lazy Tensor Core 和 Dynamo 等 PyTorch Tracing 系统)捕捉 PyTorch 的计算图,并将其统一转换为 StableHLO 的中间表示层。BladeDISC 接收一张 StableHLO 计算图通过一系列优化算法最终生成不同硬件上运行的可执行文件,BladeDISC 的优化主要涵盖以下几个方面:

  • 显存优化:基于对 Buffer 生存周期的分析,实现自动的 offloading,recomputation 等显存相关的优化。

  • 计算优化:例如算子的融合、计算图化简 以及 Custom Operator 的支持等优化计算效率。

  • 通信优化:例如 Multiple CUDA Stream 的异步通信等。

BladeDISC 还支持多种主流芯片架构,目前已涵盖Nvidia,AMD以及 Intel CPU 等主流硬件平台。

二、BladeDISC++的创新方案

正如前文中提到的面向 Dynamic Shape 计算图下的诸多挑战,PAI 团队创新性地提出了 BladeDISC++ 解决方案。

BladeDISC++简介

Figure2: BladeDISC++ Overview

在 Dynamic Shape 场景下,最核心的挑战在于缺乏具体的形状信息,这导致无法静态地完成计算图的优化算法。BladeDISC++ 采取了结合编译时和运行时进行联合优化的技术方案。

正如 Figure2 中展示的一样,BladeDISC接收到的是 TorchAcc GraphCapture 记录下来的动态形状计算图,这个计算图包含两个特点:一是输入张量的形状是未知的;二是计算图的拓扑结构是固定的。随后 BladeDISC++ 开始对 Dynamic Shape 计算图进行优化,主要包含以下核心阶段:

  • Operation Fusion

将访存算子或GEMM算子合并在一起,可以减少 Kernel 发射带来的额外开销并增加共享内存的利用率,提升系统吞吐。

  • Operation Scheduling

调整算子的执行顺序,通过优化 Tensor 生存周期降低显存峰值。

  • Automatic Rematerialization(Auto Remat)

Auto Remat 技术将临时不用的 Tensor 从 GPU HBM 中释放掉,在使用它时通过 Regenerate 技术重新生成回来,通常包含两种技术手段:

  1. Offloading 技术在显存即将超过阈值时将 GPU Tensor 从 GPU 内存转移到 CPU 内存,并在用到它之前转移回来

  2. Recomputation 技术将暂时不用的 GPU Tensor 释放掉,在用到它之前重新计算回来,是一种以时间换空间的策略。

当然这些阶段是当前 AI 编译器中较为典型的优化步骤。然而,由于缺乏具体的张量形状信息,使得现有的方法无法生效。BladeDISC++ 首先构建一个基于 Symbolic Shape 的计算图,用以表示未知的形状信息以及其关联关系。基于 Symbolic Shape Graph,BladeDISC++ 可以尽量判断张量之间所占内存的大小关系,从而调整算子执行顺序(Operation Scheduling)来降低显存峰值。对于 Auto Remat,由于缺少了具体的形状信息,编译器无法在编译期静态的决定哪些张量需要被 Offloading 或 Recomputation ,BladeDISC++ 采取了编译期和运行时联合优化的方法,在编译期选取可能被暂时释放的 Tensor,在运行期,根据实际的显存用量,动态的决定 Regenreate 的策略:offloading 或者 recomputation 。

综上所述,BladeDISC++ 通过结合编译期和运行时的联合优化方法,成功应对了动态形状下的诸多挑战,特别是在优化显存峰值方面,实现了高效的深度学习训练任务优化。

Symbolic Shape Graph

Figure3: Symbolic Shape Graph

Figure3 中的 MLIR Intermediate Representation (IR) 展示了 Dynamic Shape Graph 及其对应的 Symbolic Shape。Graph 输入%arg0的形状是未知的,使用 “?” 表示,为了便于全局分析,BladeDISC++ 引入了 SymbolicDimOp 通过 Tensor Attribution,将 Symbolic Shape 与未知 Shape 进行绑定,例如:%arg0: tensor<?, [$S0]>。

为了评估 Tensor 之间占用显存的大小关系 BladeDISC++ 基于 Symbolic Shape 构建了 Symbolic Expression (SymbolicExpr) 来描述 Tensor 的元素个数,例如:%1084和%1085:expr1 = 11008 * @S1; expr2 = 1024 * @S0。为了比较 SymbolicExpr 之间的大小关系,BladeDISC++ 通过对算子的语义以及输入输出之间的约束关系进行分析,进而化简表达式。例如对于ReshapeOp,其算子语义是将一个输入 Tensor 变换形状并输出一个新的 Tensor。同时ReshapeOp隐含了一个约束,即输入和输出 Tensor 的元素数量是一致的。基于这些信息,可以推导出形状之间的关系,例如 Figure3 中@S0 = 12 * @S1, BladeDISC++ 可以将 expr2 化简为expr2=132096 * @S0,从而推断出 expr1 小于 expr2。

Operation Scheduling

Figure4: Operation Scheduling

在 AI 编译器中,通过调整算子的调度顺序,可以有效降低显存峰值。例如,在图4中,黄色曲线表示内存使用量为1,蓝色曲线表示为2。考虑以下两种执行顺序:

  1. A→C→E→B→D→F

  2. A→C→B→D→E→F

当执行到 A→C 后,系统有两个选择:调度 B 或 E。如果选择 C→E→B 的顺序,此时活跃张量(Living Tensor)的总大小为5;而若选择 C→B→D,则活跃张量的总大小为6。由此可见,不同的调度序列会显著影响显存的峰值。

然而,在 Dynamic Shape 环境下,由于无法预先确定具体张量的大小,难以准确预估不同调度序列对活跃张量总大小的影响。为了解决这一问题,BladeDISC++ 利用前面介绍的符号表达式(SymbolicExpr)对 Tensor 占用的显存大小进行比较。例如,在上述例子中,选择调度 B 或 E 分别会导致不同的内存需求:expr1=S1 × 10,996和expr2 = S0 × 4,096。结合计算图中推导出的关系S0 = 12 × S1,可以较容易地判断出调度 E 的峰值内存更低。

当然,这仅是一种尽力而为的策略。在实际测试中,并非所有的内存大小都可以化简或直接比较。在大型语言模型(例如 LLama2)中,尽管少部分包含二次项的表达式无法进行比较,但大多数情况下,我们可以将表达式规约到相同的 SymbolicDim,从而实现有效的调度优化。

通过合理的算子调度,BladeDISC++ 能够在动态形状环境下有效降低显存峰值,提升深度学习模型的训练效率。尽管存在一些限制和挑战,但通过构建和简化符号形状计算图,BladeDISC++ 在大多数情况下能够实现显著的优化效果。

Just-In-Time Auto Rematerialization(JiT Remat)

Figure5: Jit Remat

静态形状计算图上的 Auto Remat 技术通过预估显存峰值,在计算图上找到哪些 Living Tensor 会导致显存超过某一阈值,进而搜索出哪些 Tensor 需要被释放以及 Regenerate 策略:比如 offloading 或 recomputation ,需要注意的是无论 offloading 还是 recomputation 会引入额外显存带宽占用或增加计算量,这会对端到端性能造成一定损失,所以只有在判断显存峰值可能超过阈值时才会执行 Rematerialization 操作。但是在 Dynamic Shape 环境下,由于缺少具体的 Shape 信息,无法对显存占用进行预估,BladeDISC++ 基于 Symbolic Shape 计算图采取了编译期-运行期联合优化的思路解决了这个问题。

  • 在编译期,BladeDISC++ 搜索出所有可能被释放的 Living Tensor,以及对应的 Regenerate 子图。通过在计算图上插入 EvictOp 和 RegenerateOp,表示可能对这个 Tensor 进行 Remat 操作的语义:offloading,recompute 或者什么都不做。

  • 在运行时,BladeDISC++ 根据实际 Tensor Shape 结合 Symbolic Shape Graph 对显存峰值进行预估,从而判断需要对哪些 Living Tensor 进行 Remat 操作。

Figure 6: Jit Remat Optimize Memory Peak

正如 Figure6 中所示,蓝色曲线表示优化前的显存使用情况,红色曲线则代表设定的内存限制。对于每一轮迭代,输入 Tensor 的 SymolicDim都会对应一个确定的值:例如S0=1024,S1=4,结合 Symbolic Shape Graph,BladeDISC++ 计算图的显存用量进行一次预估,当显存用量高于设定阈值时,系统将回溯检查之前的 Tensor,判断哪些 Tensor 需要 Remat,并依据端到端损失最小的原则,选择 offloading 还是 recompute 策略。优化后的黄色曲线尽可能地保持显存用量在设定的限制以下。然而值得注意的是这种优化算法并不能在所有情况下都确保内存使用低于限制,仅在训练集配置下,用尽量少的 GPU 资源处理更大规模的训练数据。

三、性能评估

Figure7: Evaluation on Llama2

为了方便在单卡上进行验证,我们在 Llama2-7B 上进行了一些裁剪(hidden_layers=4)使其变为1B 模型。如 Figure7 所示,我们做了如下实验:

  • Dynamic Shape BladeDISC 在 Dynamic Shape 环境没有显存优化

  • Static Shape BladeDISC 在 Static Shape 环境显存优化的实验

  • BladeDISC++ 在 Dynamic Shape 环境开启了显存优化(本篇工作)

注:为了避免 Static Shape 下不同的输入 Tensor Shape 都编译一张计算图,所以实验中对数据采取了分桶 padding 的策略避免编译次数过多带来的overhead[3].

实验数据表明,在 BatchSize=14 时,BladeDISC++ 吞吐基本和 Dynamic Shape 持平,显存峰值和 Static Shape 情况持平。当 BatchSize 增大到 18 时,Dynamic Shape 由于没有显存优化策略会导致 Out of Memory (OOM), Static Shape 开启了显存优化能够将训练任务跑起来,但由于 padding 带来的冗余计算,导致吞吐只有 5103 tokens/sec,而 BladeDISC++ 显存峰值和 Static Shape 下基本一致,但吞吐提升了 11%。

四、总结

Dynamic Shape 环境下核心的挑战是 Tensor Shape 的不确定性,BladeDISC++ 构建了 Symbolic Shape Graph 来描述 Dynamic Shape 之间的关系,在此基础上提出了基于 Symbolic Shape 的 Operation Scheduling 以及编译-运行时联合优化的 Jit Auto Rematerialization 方法。在 Llama2 模型上的实验数据表明,BladeDISC++ 能够有效降低训练时的显存占用,优化效果可以与 Static Shape 环境相媲美,同时由于避免了冗余计算,吞吐优于 Static Shape。以上就是 PAI 团队在近期在 Dynamic Shape 环境下的显存优化方向的一些探索,

本文分享了我们在优化动态形状计算图显存方面的行业经验。我们提出了基于符号形状的算子调度和重材化方法,并开发了 BladeDISC++。评估结果表明,BladeDISC++ 能够有效降低动态形状训练的显存使用,并且在显存优化效果上可与静态形状训练相媲美。据我们所知,这是该领域的开创性工作,我们希望它能够支持编译器社区管理动态形状工作负载,促进动态形状编译器的更广泛应用。

加入我们

PAI 核心引擎团队团队社招、实习火热招聘中,包括三个方向:

  • AI 编译器

    • 基于 MLIR 的自研编译器 BladeDISC,极致优化 GPU 计算效率。

    • OpenAI Triton,训练、推理场景中的算子调优以及运行时优化。

  • 大模型训练优化

    • 包括 LLM,VLM、 MoE 以及视频图像生成等主流模型大规模训练任务的优化,包括算子优化、分布式并行策略优化、框架优化等。

  • 大模型推理优化

    • LLM、VLM 以及MoE 等主流模型的推理系统的端到端优化,包括且不限于算子调优、量化压缩、调度优化以及框架优化等。

如果您对以上任何一个方向感兴趣,欢迎投递简历到 PAI 核心引擎团队招聘贴 或直接发邮件到 yancey.yx@alibaba-inc.com 。

也欢迎通过 Github 上 BladeDISC issue或 TorchAcc issue 与我们沟通,或者加入钉钉群一起交流 AI Infra 相关问题:

BladeDISC用户支持群:44534789

TorchAcc 开源用户交流群:105600001423

引用

  • [1] GitHub - alibaba/BladeDISC: An end-to-end DynamIc Shape Compiler project for machine learning workloads. GitHub. https://github.com/alibaba/BladeDISC

  • [2] GitHub - AlibabaPAI/torchacc: PyTorch distributed training acceleration framework. GitHub. https://github.com/alibabapai/torchacc

  • [3] Source of recompilations in Pytorch/XLA — PyTorch/XLA master documentation. (n.d.). Source of recompilations in Pytorch/XLA — PyTorch/XLA master documentation

相关文章:

BladeDISC++:Dynamic Shape AI 编译器下的显存优化技术

近年来&#xff0c;随着深度学习技术的迅猛发展&#xff0c;越来越多的模型展现出动态特性&#xff0c;这引发了对动态形状深度学习编译器(Dynamic Shape AI Compiler)的广泛关注。本文将介绍阿里云 PAI 团队近期发布的 BladeDISC项目&#xff0c;探讨在动态场景下如何优化深度…...

FFmpeg常用命令

文章目录 一、 FFmpeg 音视频的处理流程二、FFmpeg 常用命令2.1、查看本机支持的采集设备2.2、 录制视频2.2.1、原始视频2.2.2、编码的视频 2.3、录制音频&#xff1a;2.3.1、原始音频2.3.2、编码的音频 2.4、录制音视频&#xff1a;2.5、文件格式转换&#xff1a;2.6、提取音频…...

http请求开启长连接导致请求偶发失败

问题描述&#xff1a; http长连接的意思是服务器为了调用时减少TCP三次握手开销&#xff0c;会复用之前已经发起的请求&#xff0c;比较适合频繁交互&#xff08;比如数据推送、流水线操作等&#xff09;的场景&#xff0c;但是如果超过服务器配置的连接最大空闲时间&#xff0…...

JUnit单元测试

单元测试 就是针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;编写测试代码对其正确性进行测试 JUnit 最流行的java测试框架之一&#xff0c;方柏霓进行单元测试 入门程序 使用Junit&#xff0c;对UserService的方法进行单元测试 1.在pom.xml中&#xff0c;…...

智慧公安(实景三维公安基层基础平台)建设方案——第4章

4 建设内容 4.1 标准规范体系 在国家和地方公安基层信息化标准规范的基础上,结合项目实际情况,制定标准规范及管理制度,构建统一的标准规范体系,以便更好地实现公安基层基础信息的高度共享、平台运行的统一协调、业务流程最优化。主要包括以下内容: 1. 业务标准规范 (…...

LLMs(大型语言模型)的多智能体:Auto-GPT

LLMs(大型语言模型)的多智能体:Auto-GPT 是指在一个系统中集成多个具有不同能力、角色和任务的智能体,这些智能体能够相互协作、沟通和交互,以共同完成复杂的任务或解决复杂的问题。每个智能体都可以被视为一个独立的实体,具有自己的策略、目标和知识库,通过相互之间的…...

《Effective Java》学习笔记——第2部分 对象通用方法最佳实践

文章目录 第2部分 所有对象通用方法一、前言二、最佳实践内容1. equals()方法2. hashCode()方法3. toString() 方法4. clone() 方法5. finalize() 方法6. compareTo()方法&#xff08;实现 Comparable 接口&#xff09; 三、小结 第2部分 所有对象通用方法 一、前言 《Effect…...

2024年智慧消防一体化安全管控年度回顾与2025年预测

随着科技的飞速发展&#xff0c;智慧营区一体化安全管控在2024年取得了显著进展&#xff0c;同时也为2025年的发展奠定了坚实基础。 2024年年度回顾 政策支持力度持续加大&#xff1a;国家对消防安全的重视程度不断提高&#xff0c;出台了一系列涵盖技术创新、市场应用、人才培…...

艺术家迟首飞在特殊历史时刻展现中国艺术力量

艺术家迟首飞在特殊历史时刻展现中国艺术力量 艺术创作的边界正被不断拓展。中国艺术家迟首飞以其纪实视野&#xff0c;将传统与现代元素巧妙融合&#xff0c;展现全球艺坛力量&#xff0c;创作出一系列精彩作品。尤其是《平安兔》《福》与TikTok标志的结合的作品&#xff0c;…...

探索微服务架构:从单体应用到微服务的转变

引言 随着互联网业务的日益复杂和用户需求的快速增长&#xff0c;软件开发的架构模式也在不断演进。从最早的单体应用架构到后来的分层架构&#xff0c;再到如今备受关注的微服务架构&#xff0c;每一种架构模式都试图解决软件开发中的不同挑战。尤其是在现代互联网企业中&…...

MongoDB vs Redis:相似与区别

前言 在当今的数据库领域&#xff0c;MongoDB 和 Redis 都是备受关注的非关系型数据库&#xff08;NoSQL&#xff09;&#xff0c;它们各自具有独特的优势和适用场景。本文将深入探讨 MongoDB 和 Redis 的特点&#xff0c;并详细对比它们之间的相似之处和区别&#xff0c;帮助…...

Jenkins-pipeline语法说明

一. 简述&#xff1a; Jenkins Pipeline 是一种持续集成和持续交付&#xff08;CI/CD&#xff09;工具&#xff0c;它允许用户通过代码定义构建、测试和部署流程。 二. 关于jenkinsfile&#xff1a; 1. Sections部分&#xff1a; Pipeline里的Sections通常包含一个或多个Direc…...

MySQL(3)运算符、排序与分页

运算符 一、算术运算符 加减乘除余 举例&#xff1a; SELECT 1001 FROM DUAL; 结果为101&#xff0c;与java中的连接字符串不同。 SELECT 100A FROM DUAL; 结果为100。 也可以理解为&#xff0c;遇到非数值类型时&#xff0c;先转换为数值类型&#xff08;如2可以转换…...

Kafka面试题----Kafka消息是采用Pull模式,还是Push模式

Pull 模式为主 消费者主动拉取&#xff1a;Kafka 中的消费者是基于 Pull 模式来获取消息的。消费者通过向 Kafka 集群发送拉取请求&#xff0c;主动地从 Broker 中获取消息。这种方式使得消费者可以根据自身的消费能力和处理速度来灵活地控制消息的拉取频率和数量&#xff0c;…...

BLE透传方案,IoT短距无线通信的“中坚力量”

在物联网&#xff08;IoT&#xff09;短距无线通信生态系统中&#xff0c;低功耗蓝牙&#xff08;BLE&#xff09;数据透传是一种无需任何网络或基础设施即可完成双向通信的技术。其主要通过简单操作串口的方式进行无线数据传输&#xff0c;最高能满足2Mbps的数据传输速率&…...

借助 .pth 文件完成多个 Python 解释器的合并

相关搜索 conda 虚拟环境如何使用 ROS 的 Python 模块conda 虚拟环境找不到 catkin_pkg 问题描述 如果你在 Ubuntu 20.04 中装了 conda&#xff0c;那么你的 Ubuntu 会有这些 Python 解释器&#xff1a; /usr/bin/python3&#xff1a;系统的解释器 (版本为 3.8.10&#xff0…...

今天也是记录小程序进展的一天(破晓时8)

嗨嗨嗨朋友们&#xff0c;今天又来记录一下小程序的进展啦&#xff01;真是太激动了&#xff0c;项目又迈出了重要的一步&#xff0c;231啦&#xff01;感觉每一步的努力都在积累&#xff0c;功能逐渐完善&#xff0c;离最终上线的目标越来越近了。大家一直支持着这个项目&…...

python高级加密算法AES对信息进行加密和解密

AES&#xff08;高级加密标准&#xff09;是一种广泛使用的对称加密算法&#xff0c;它以字节为单位处理数据&#xff0c;将明文分组加密成密文。AES算法的核心在于一个轮函数&#xff0c;该函数会对数据执行多次变换&#xff0c;包括字节代换、行移位、列混合和轮密钥加。这些…...

# [Unity]【游戏开发】 脚本生命周期与常见事件方法

在Unity中,脚本的生命周期是指脚本从创建到销毁的整个过程,以及在此过程中触发的各类事件。掌握脚本生命周期对优化游戏开发过程和避免性能问题至关重要。本文将详细探讨脚本生命周期的关键事件、常见的事件方法,并通过实例说明如何在合适的时机执行脚本逻辑,以确保游戏的流…...

《探秘鸿蒙Next:非结构化数据处理与模型轻量化的完美适配》

在鸿蒙Next的人工智能应用场景中&#xff0c;处理非结构化数据并使其适配模型轻量化需求是一项关键且具有挑战性的任务。以下是一些有效的方法和策略。 数据预处理 数据清洗&#xff1a;非结构化数据中往往存在噪声、重复和错误数据。对于文本数据&#xff0c;要去除乱码、特殊…...

Spring Boot框架下的上海特产销售商城网站开发之旅

摘要 本项目基于Spring Boot框架开发&#xff0c;旨在创建一个网络上海特产销售商城网站。在黄菊华老师的指导下&#xff0c;该项目不仅涵盖了核心代码讲解和答辩指导&#xff0c;还提供了详尽的开发文档、开题报告、任务书及PPT等毕业设计辅导材料。黄老师是《Vue.js入门与商城…...

HTML 基础入门:核心标签全解析

在网页开发的世界里&#xff0c;HTML&#xff08;超文本标记语言&#xff09;是基石般的存在。它负责构建网页的基本结构&#xff0c;为用户呈现出丰富多样的内容。今天&#xff0c;就让我们一起深入了解 HTML 中几个极为关键的基础标签&#xff0c;开启网页创作的第一步。 一…...

Docker基础安装与使用

Docker 简介 Docker 是一个开源的容器化平台&#xff0c;用于开发、部署和运行应用程序。它通过将应用程序及其依赖项打包到一个轻量级的、可移植的容器中&#xff0c;实现了应用程序的快速部署和跨环境一致性。 Docker 的核心概念 容器&#xff08;Container&#xff09;&a…...

基于Docker的Spark分布式集群

目录 1. 说明 2. 服务器规划 3. 步骤 3.1 要点 3.2 配置文件 3.2 访问Spark Master 4. 使用测试 5. 参考 1. 说明 以docker容器方式实现apache spark计算集群&#xff0c;能灵活的增减配置与worker数目。 2. 服务器规划 服务器 (1master, 3workers) ip开放端口备注ce…...

物业管理软件引领智能社区高效服务与管理创新

内容概要 物业管理软件是在智能社区建设中不可或缺的重要工具。随着城市化进程的加速&#xff0c;社区管理的复杂性也在不断上升&#xff0c;如何提高服务效率和管理水平&#xff0c;已经成为物业公司面临的主要挑战。在这样的背景下&#xff0c;物业管理软件以其强大的功能和…...

NoETL | 数据虚拟化如何在数据不移动的情况下实现媲美物理移动的实时交付?

在我们之前的文章中&#xff0c;我们回顾了Denodo在逻辑数据仓库和逻辑数据湖场景中所使用的主要优化技术&#xff08;具体内容请参阅之前的文章&#xff09;。 数据架构 | 逻辑数据仓库与物理数据仓库性能对比_物理数仓、逻辑数仓-CSDN博客文章浏览阅读1.5k次&#xff0c;点赞…...

ovs实现lb负载均衡

负载均衡定义 负载均衡器的实现原理是通过硬件或软件设备将客户端访问流量根据转发策略分发到多个服务器或设备上&#xff0c;以确保系统的负载均衡。常见的实现方式包括&#xff1a; 二层负载均衡‌&#xff1a;使用虚拟MAC地址方式&#xff0c;根据OSI模型的二层进行负载均…...

2025 OWASP十大智能合约漏洞

随着去中心化金融&#xff08;DeFi&#xff09;和区块链技术的不断发展&#xff0c;智能合约安全的重要性愈发凸显。在此背景下&#xff0c;开放网络应用安全项目&#xff08;OWASP&#xff09;发布了备受期待的《2025年智能合约十大漏洞》报告。 这份最新报告反映了不断演变的…...

在亚马逊云科技上用AI提示词优化功能写出漂亮提示词(下)

提示工程&#xff08;Prompt Engineering&#xff09;对各位小伙伴们来说是再熟悉不过了&#xff0c;提示词工程技术是通过编写指令词&#xff0c;指导开发者们调用AI基础模型&#xff08;FMs&#xff09;获得期望的响应。但是经常写提示词的朋友们会知道&#xff0c;为了获取理…...

智能鞋利用机器学习和深度学习技术进行患者监测和步态分析的演变与挑战

概述 近年来&#xff0c;创新型 "智能鞋 "层出不穷&#xff0c;将物联网&#xff08;IoT&#xff09;和可穿戴设备技术融入 "鞋 "中&#xff0c;成为我们日常生活中不可或缺的一部分。智能鞋可以通过鞋中嵌入的电子元件、传感器、微处理器和其他技术&…...

Unity编辑拓展显示自定义类型

配合自定义特性或着header可以添加注解 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Reflection; using System; using Unity.VisualScripting;#if UNITY_EDITORpublic class EditorRender {public sta…...

Unity预制体未即时刷新

有时候在用代码修改预制体某个组件中的属性时&#xff0c;可能原本预制体未及时刷新&#xff1a; 可以使用PrefabUtility.SavePrefabAsset(gameobject)等函数&#xff0c;使得使用代码修改之后马上刷新生效。 一、AssetDatabase.Refresh() 功能&#xff1a; AssetDatabase.Re…...

SSO VS OAuth2区别

目录 理解认证与授权 Single Sign On(SSO) ​编辑 OAuth2 OAuth2协议理解 Access Token的秘密 SSO与OAuth2的关系 理解认证与授权 Single Sign On(SSO) 示例图 1、用户通过浏览器访问系统 Protected APP&#xff08;Goto app&#xff09; 2、Protected APP 发现没有登录…...

12_PlayerPrefs存储登录窗口逻辑_回调函数优化Lamd表达式

创建 登录窗口LoginWnd.cs 绑定 登录窗口LoginWnd.cs 编写 登录窗口LoginWnd.cs using UnityEngine; using UnityEngine.UI; //输入文本 命名空间 //功能 : 登录注册窗口 public class LoginWnd : MonoBehaviour{public InputField iptAcct;public InputField iptPass;public …...

蒙操作系统(HarmonyOS)

鸿蒙操作系统&#xff08;HarmonyOS&#xff09;是由华为技术有限公司开发的面向未来、面向全场景的分布式操作系统。它旨在为各种不同类型的设备提供统一的操作系统和无缝的智能体验&#xff0c;从智能手机到可穿戴设备&#xff0c;再到智能家居产品等。在鸿蒙的应用生态中&am…...

PHP同城配送小程序

&#x1f680; 同城极速达——您生活中的极速配送大师 &#x1f4f1; 一款专为现代都市快节奏生活量身打造的同城配送小程序&#xff0c;同城极速达&#xff0c;集高效、便捷、智能于一身&#xff0c;依托ThinkPHPGatewayWorkerUniapp的强大架构&#xff0c;巧妙融合用户端、骑…...

C#语言的学习路线

C#语言的学习路线 C#作为一种现代编程语言&#xff0c;凭借其简洁的语法、强大的功能和广泛的应用&#xff0c;得到了越来越多开发者的青睐。无论是开发桌面应用、Web应用、游戏&#xff0c;还是云服务&#xff0c;C#都有着广泛的应用场景。本文将为有志于学习C#的读者提供一条…...

js手写-实现Promise的then方法

简单引入then 代码 const PROMISE_STATUS_PENDING "pending";const PROMISE_STATUS_FULFILLED "fulfilled";const PROMISE_STATUS_REJECTED "rejected";class MyPromise {constructor(executor) {//status -- 存储promise的状态this.status…...

分布式系统通信解决方案:Netty Marshalling 全面解析

分布式系统通信解决方案&#xff1a;Netty Marshalling 全面解析 一、引言 在现代网络编程中&#xff0c;Netty 作为一款高性能、异步事件驱动的网络应用框架&#xff0c;因其强大的功能和灵活的扩展性&#xff0c;备受开发者青睐。Netty 广泛应用于分布式系统、RPC 框架以及…...

如何轻松实现域名指向服务器

在互联网时代&#xff0c;域名指向服务器是网站上线的关键步骤。域名是用户访问网站的入口&#xff0c;而服务器则是存储网站数据的地方。将域名正确指向服务器&#xff0c;能让用户顺利访问网站内容。虽然这个过程对新手来说可能有些陌生&#xff0c;但只要掌握正确的方法&…...

Java Web开发高级——单元测试与集成测试

测试是软件开发的重要环节&#xff0c;确保代码质量和功能的正确性。在Spring Boot项目中&#xff0c;单元测试和集成测试是常用的两种测试类型&#xff1a; 单元测试&#xff1a;测试单个模块&#xff08;如类或方法&#xff09;是否按预期工作。集成测试&#xff1a;测试多个…...

第九篇: 3.10. 【watchEffect】实现监听,立即执行函数

官网&#xff1a;立即运行一个函数&#xff0c;同时响应式地追踪其依赖&#xff0c;并在依赖更改时重新执行该函数。 watch对比watchEffect 都能监听响应式数据的变化&#xff0c;不同的是监听数据变化的方式不同 watch&#xff1a;要明确指出监视的数据 watchEffect&#x…...

【C++】模板(进阶)

本篇我们来介绍更多关于C模板的知识。模板初阶移步至&#xff1a;【C】模板&#xff08;初阶&#xff09; 1.非类型模板参数 1.1 非类型模板参数介绍 模板参数可以是类型形参&#xff0c;也可以是非类型形参。类型形参就是我们目前接触到的一些模板参数。 //类型模板参数 …...

有了TiDB,是否还需要“散装”大数据组件?

有了TiDB&#xff0c;是否还需要“散装”大数据组件&#xff1f; 最近和同事们讨论一个问题&#xff1a;在大数据应用日益增多的今天&#xff0c;如果使用了TiDB这样的一体化数据库&#xff0c;还需要使用那些传统的大数据组件&#xff08;比如Hadoop、Spark等&#xff09;吗&…...

OSCP - Proving Grounds - BullyBox

主要知识点 如果发现有域名&#xff0c;则可以加入/etc/hosts后重新执行nmap,nikto等扫描dirsearch的时候可以使用完整一些的字典文件&#xff0c;避免漏掉信息.git dump 具体步骤 执行nmap 扫描&#xff0c;发现 80和22端口开放,访问后发现被重定向到 bullybox.local Star…...

升级《在线写python》小程序的分享功能。昨天忘了...

小程序是使用uniapp写的&#xff0c;忘了开启分享功能&#xff0c;导致它现在是这样的。 挺不方便的&#xff0c;所以需要开启分享权限&#xff0c; 由于我这个没有其他需要隐藏的私密页面&#xff0c;所以事直接全局开启就行 在App.vue文件里的onShow里开启即可。加入如下代…...

Spingboot整合Netty,简单示例

Netty介绍在文章末尾 Netty介绍 项目背景 传统socket通信&#xff0c;有需要自身管理整个状态&#xff0c;业务繁杂等问题。 pom.xml <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.117.F…...

逆波兰表达式求值(力扣150)

这道题也是一道经典的栈应用题。为什么这样说呢&#xff1f;我们可以发现&#xff0c;当我们遍历到运算符号的时候&#xff0c;我们就需要操控这个运算符之前的两个相邻的数。这里相邻数不仅仅指最初数组里相邻的数&#xff0c;在进行了运算之后&#xff0c;得到的结果与后面的…...

Linux面试题

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

如何判断以太坊地址类型?

如何判断以太坊地址类型&#xff1f; 一、账户类型解释 2.1 以太坊外部账户&#xff08;Externally Owned Account&#xff0c;EOA&#xff09; 外部账户&#xff08;EOA&#xff09;是由私钥控制的账户&#xff0c;在以太坊网络中用来发送交易和执行其他操作。EOA 不是智能…...