一键多环境构建——用 Hvigor 玩转 HarmonyOS Next
引言
在 HarmonyOS Next 的应用开发中,常常需要针对不同环境(测试、预发、线上)或不同签名(调试、正式)输出多个 APP/HAP 包。虽然 HarmonyOS 提供了多目标构建(Multi-Target Build)能力,可以在同一项目里配置多个 product 并生成不同包名的多个产物,但某些深度定制(如动态修改 module.json5
中的 client_id
、app_id
,或基于构建时间改写输出包名)仍需借助自定义 Hvigor 插件来完成。
结合示例项目,演示如何通过 Hvigor 插件配合多目标构建,实现:
- 统一管理各环境的 API 地址、埋点地址等配置;
- 动态注入
clientId
、appId
等应用信息; - 基于构建时间和 product 名称,定制化输出包名,便于后续上架和线上排查。
一、在项目中使用 Hvigor 自定义插件
1. Hvigor 插件的入口
在 HarmonyOS 项目根目录存在入口文件 hvigorfile.ts
,将自定义 task 注册到 plugins
中:
// 文件:hvigorfile.ts
import { buildSchemaProcessing } from './scripts/build-schema-processing';export default {system: appTasks, // Hvigor 内置任务,不可修改plugins: [buildSchemaProcessing() // 自定义插件:动态修改 module.json5、build-profile.json5 等]
};
点击 DevEco Studio 上方的 Sync Now 或执行 hvigor sync
,即可将插件加载到构建流程中。
2. Hvigor 常用 API 概览
在自定义插件代码中,我们通常会用到以下核心 API:
hvigor.getRootNode()
:获取根节点,进而拿到各插件上下文rootNode.getContext(pluginId)
:获取指定插件的上下文对象,例如OHOS_APP_PLUGIN
、OHOS_HAP_PLUGIN
context.getAppJsonOpt()
/getModuleJsonOpt()
:读取app.json5
或module.json5
的 AST 对象context.getBuildProfileOpt()
:读取根目录build-profile.json5
的 AST 对象context.setAppJsonOpt()
/setBuildProfileOpt()
:将修改后的 AST 写回,生效于后续构建
// 示例:读取上下文
const root = hvigor.getRootNode();
const appCtx = root.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;
const hapCtx = root.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosAppContext;
const appJson = appCtx.getAppJsonOpt();
const modJson = hapCtx.getModuleJsonOpt();
const buildProfile = appCtx.getBuildProfileOpt();// 修改后需要重新 set 回去
appCtx.setAppJsonOpt(appJson);
appCtx.setBuildProfileOpt(buildProfile);
二、结合多目标构建与自定义插件 实现环境切换
1. 规范 Product 命名
为了脚本中便于解析,我们约定 product
的 name
采用下划线分隔、固定格式:
<应用标识>_<签名标识>_<环境标识>
例如:demo1_debug_test、demo1_release_preRelease、demo2_debug_official
在 build-profile.json5
中配置多个 product:
"products": [{"name": "demo1_debug_test","signingConfig": "debug","buildOption": {"arkOptions": {"buildProfileFields": {"productsName": "demo1","buildTime": "","apiUrl": "","trackApiUrl": ""}}}},{"name": "demo1_release_officiallyReleased","signingConfig": "release","buildOption": { /* 同上 */ }},/* 更多 product 配置… */
]
Tip:
buildProfileFields
下的字段会被注入到应用运行时,便于在代码中读取环境信息。
2. 本地配置文件:config.json
将各环境的 API 地址,以及各应用的 clientId
/appId
信息集中管理:
{"environmentInfo": {"test": {"apiUrl": "https://api.test.com","trackApiUrl": "https://stat.test.com"},"preRelease": {"apiUrl": "https://api-pre.example.com","trackApiUrl": "https://stat-pre.example.com"},"officiallyReleased": {"apiUrl": "https://api.prod.com","trackApiUrl": "https://stat.prod.com"}},"appConfigInfo": {"demo1": {"clientId": "111898773","appId": "5765880207855284373"},"demo2": {"clientId": "6917571239128090930","appId": "6917571239128090930"}}
}
并提供两个辅助函数,在插件中使用:
// scripts/config.ts
import cfgRaw from '../config.json';
import { format } from 'date-fns';export function formatBuildTime(date = new Date()): string {const pad = (n: number) => String(n).padStart(2, '0');return `${date.getFullYear()}-${pad(date.getMonth()+1)}-${pad(date.getDate())}`+ `_${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
}export function getLocalConfig() {const cfg = JSON.parse(JSON.stringify(cfgRaw));cfg.buildTime = formatBuildTime();return cfg;
}
3. 插件实现核心逻辑
在 build-schema-processing.ts
中,利用 Hvigor 生命周期钩子完成配置注入与产物重命名。
// scripts/build-schema-processing.ts
import { getLocalConfig } from './config';export function buildSchemaProcessing() {const localCfg = getLocalConfig();let currentProduct = '', versionName = '', bundleName = '', appConfig: any;return {pluginId: 'custom-build-processor',apply(hvigor) {hvigor.getRootNode().afterNodeEvaluate(root => {// 获取上下文const appCtx = root.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;const hapCtx = root.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosAppContext;const buildProfile = appCtx.getBuildProfileOpt();const appJson = appCtx.getAppJsonOpt();const modJson = hapCtx.getModuleJsonOpt();// 当前 product 信息currentProduct = appCtx.getCurrentProduct().getProductName() || '';versionName = appJson.app.versionName;const productKeys = currentProduct.split('_');const appKey = productKeys[0];const envKey = productKeys[2];appConfig = localCfg.appConfigInfo[appKey];const envConfig = localCfg.environmentInfo[envKey];// 注入 app.json5 中的 clientId、appIdif (modJson) {modJson['module']['appId'] = appConfig.appId;modJson['module']['clientId'] = appConfig.clientId;hapCtx.setModuleJsonOpt(modJson);}// 遍历各 product,注入环境 & 时间 & 重命名 artifact(buildProfile.app.products || []).forEach((prd: any) => {prd.buildOption.arkOptions.buildProfileFields.buildTime = localCfg.buildTime;prd.buildOption.arkOptions.buildProfileFields.apiUrl = envConfig.apiUrl;prd.buildOption.arkOptions.buildProfileFields.trackApiUrl= envConfig.trackApiUrl;const suffix = `${appKey}_${versionName}_${localCfg.buildTime}`;if (prd.name === currentProduct) {bundleName = prd.bundleName || appJson.app.bundleName;}prd.output.artifactName = `AtomicPlatform-${suffix}`;});appCtx.setBuildProfileOpt(buildProfile);});hvigor.buildFinished(() => {console.log(`📅 构建时间: ${localCfg.buildTime}`);console.log(`📦 当前产物: ${currentProduct}`);console.log(`🔖 包名(bundleName): ${bundleName}`);console.log(`🆔 ClientID: ${appConfig.clientId}`);console.log(`🆔 AppID: ${appConfig.appId}`);});}};
}
三、运行效果与日志验证
执行 hvigor build
,在日志中即可看到注入与重命名结果:
====================== 编译包信息 ======================
📅 构建时间: 2025-04-24_09-32-05
📦 当前产物: demo2_debug_test
🔖 包名: com.atomicservice.6917571239128090930
🆔 ClientID: 6917571239128090930
🆔 AppID: 6917571239128090930
====================================================
同时,输出的 HAP 包会命名为:
AtomicPlatform-demo2_1.0.0_2025-04-24_09-32-05.hap
通过上述方式,每次在不同 product 与环境下编译,都能自动完成配置注入与产物重命名,极大提升了多环境多签名的开发与发布效率。
四、总结
- 统一管理:将环境信息、应用信息集中在
config.json
,便于维护与扩展; - 自动注入:借助 Hvigor 插件,在构建阶段动态修改
module.json5
、build-profile.json5
,免去手动切换; - 定制产物:基于构建时间与 product 名称,自定义输出包名,方便版本追踪与线上排查。
未来可在插件中进一步添加:
- 构建报告自动上传到 CI/CD 平台;
- 自动生成构建差异对比的 HTML 报告;
- 与 Git 提交、发布流程集成,构建完成自动触发审核或推送。
五、源码仓库
仓库分支参考:feature/hvigorfileBuild
仓库地址:MultiBuildDemo: 构建多目标产物 - Gitee.com
六、参考文档
扩展构建-编译构建-DevEco Studio - 华为HarmonyOS开发者
HarmonyOS Next 编译之如何构建不同包名应用在日常的开发中涉及到多签名和多产物构建输出时手动切换签名文件和包 - 掘金
HarmonyOS多环境+多渠道+自定义路径输出+自定义名称一键打app和hap包前言 做移动端开发时,不可避免的会遇到 - 掘金
sumer/cn/doc/harmonyos-guides/ide-build-expanding)
HarmonyOS Next 编译之如何构建不同包名应用在日常的开发中涉及到多签名和多产物构建输出时手动切换签名文件和包 - 掘金
HarmonyOS多环境+多渠道+自定义路径输出+自定义名称一键打app和hap包前言 做移动端开发时,不可避免的会遇到 - 掘金
相关文章:
一键多环境构建——用 Hvigor 玩转 HarmonyOS Next
引言 在 HarmonyOS Next 的应用开发中,常常需要针对不同环境(测试、预发、线上)或不同签名(调试、正式)输出多个 APP/HAP 包。虽然 HarmonyOS 提供了多目标构建(Multi-Target Build)能力&#…...
SQLPandas刷题(LeetCode3451.查找无效的IP地址)
描述:LeetCode3451.查找无效的IP地址 表:logs ---------------------- | Column Name | Type | ---------------------- | log_id | int | | ip | varchar | | status_code | int | ---------------------- log_id 是这张表的唯…...
【leetcode100】组合总和Ⅳ
1、题目描述 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1: 输入:nums [1,2,3], target 4 输出࿱…...
2020-06-23 暑期学习日更计划(机器学习入门之路(资源汇总)+概率论)
机器学习入门 前言 说实话,机器学习想学好真心不易,很多时候都感觉自己学得云里雾里。以前一段时间自己为了完成毕业设计,在机器学习的理论部分并没有深究,仅仅通过TensorFlow框架力求快速实现模型。现在来看,很多时候…...
Linux操作系统--基础I/O(上)
目录 1.回顾C文件接口 stdin、stdout、stderr 2.系统文件I/O 3.接口介绍 4.open函数返回值 5.文件描述符fd 5.1 0&1&2 1.回顾C文件接口 hello.c写文件 #include<stdio.h> #include<string.h>int main() {FILE *fp fopen("myfile","…...
Spring boot 中的IOC容器对Bean的管理
Spring Boot 中 IOC 容器对 Bean 的管理,涵盖从容器启动到 Bean 的生命周期管理的全流程。 步骤 1:理解 Spring Boot 的容器启动 Spring Boot 的 IOC 容器基于 ApplicationContext,在应用启动时自动初始化。 入口类:通过 SpringB…...
ARINC818协议一些说明综述
关键术语 航空总线技术 光纤通道层次架构 光纤通道拓扑结构 FC-AV协议,架构,容器系统 ARINC818协议,容器 ADVB帧映射,帧格式 机载视频处理系统对视频数据进行实时处理和记录。 分辨率:1080p,4k,8k视频技术 FC-AV技术是…...
Turso:一个基于 libSQL的分布式数据库
Turso 是一个完全托管的数据库平台,支持在一个组织中创建高达数十万个数据库,并且可以复制到任何地点,包括你自己的服务器,以实现微秒级的访问延迟。你可以通过Turso CLI(命令行界面)管理群组、数据库和API…...
2025.5.4机器学习笔记:PINN文献阅读
2025.5.4周报 文献阅读题目信息摘要创新点网络架构实验结论不足以及展望 文献阅读 题目信息 题目: Physics-Informed Neural Network Approach for Solving the One-Dimensional Unsteady Shallow-Water Equations in Riverine Systems期刊: Journal o…...
一行命令打开iOS模拟器
要在 Mac 命令行打开 iPhone 15 Pro 模拟器,需满足已安装 Xcode 这一前提条件,以下是具体操作步骤: 步骤一:列出所有可用模拟器设备 打开终端(Terminal),输入并执行以下命令,用于列…...
java面向对象编程【基础篇】之基础语法
目录 🚀前言🌟构造器💯案例 🤔this关键字💯使用this调用本类中的属性💯使用this调用构造器💯this表示当前对象 🦜封装💯合理隐藏💯合理暴露 🐧实体…...
跑MPS产生委外采购申请(成品)
问题:跑MPS产生委外采购申请(成品),更改BOM和跑MRP,但物料需求清单中无新增物料复合膜的需求。截图如下: 解决方法:更改委外采购申请的批准日期为BOM的生效日和重新展开bom。 重新展开后&#x…...
[flutter]切换国内源(window)
如题,切换到国内源避免总是连不上google导致卡住的问题。 临时切换到国内: cmd set PUB_HOSTED_URLhttps://pub.flutter-io.cn set FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cnpower shell $env:PUB_HOSTED_URL "https://pub.flut…...
学习海康VisionMaster之顶点检测
一:进一步学习了 今天学习下VisionMaster中的顶点检测:可检测图像指定区域内的顶点,并输出顶点坐标等信息。该模块常用于检测目标物体的顶点 二:开始学习 1:什么是顶点检测? 一个不是很规则的物体需要检测…...
Vue2中常用的核心函数(选项和生命周期钩子)的完整示例及总结
以下是Vue2中常用的核心函数(选项和生命周期钩子)的完整示例及总结: 1. 实例选项函数 data 初始化组件数据 new Vue({el: #app,data() {return {message: Hello Vue!};} });methods 定义组件方法 new Vue({el: #app,data() {return { c…...
数据集-目标检测系列- F35 战斗机 检测数据集 F35 plane >> DataBall
数据集-目标检测系列- F35 战斗机 检测数据集 F35 plane >> DataBall DataBall 助力快速掌握数据集的信息和使用方式。 贵在坚持! * 相关项目 1)数据集可视化项目:gitcode: https://gitcode.com/DataBall/DataBall-detections-100s…...
2025年3月AGI技术月评|技术突破重构数字世界底层逻辑
〔更多精彩AI内容,尽在 「魔方AI空间」 ,引领AIGC科技时代〕 本文作者:猫先生 ——当「无限照片」遇上「可控试穿」,我们正在见证怎样的智能革命? 被低估的进化:开源力量改写游戏规则 当巨头们在AGI赛道…...
【k8s】k8s是怎么实现自动扩缩的
Kubernetes 提供了多种自动扩缩容机制,主要包括 Pod 水平自动扩缩(HPA)、垂直 Pod 自动扩缩(VPA) 和 集群自动扩缩(Cluster Autoscaler)。以下是它们的实现原理和配置方法: 1. Pod …...
协作开发攻略:Git全面使用指南 — 引言
协作开发攻略:Git全面使用指南 — 引言 Git 是一种分布式版本控制系统,用于跟踪文件和目录的变更。它能帮助开发者有效管理代码版本,支持多人协作开发,方便代码合并与冲突解决,广泛应用于软件开发领域。 文中内容仅限技…...
【AI提示词】私人教练
提示说明 以专业且细致的方式帮助客户实现健康与健身目标,提升整体生活质量。 提示词 # Role: 私人教练## Profile - language: 中文 - description: 以专业且细致的方式帮助客户实现健康与健身目标,提升整体生活质量 - background: 具备丰富的健身经…...
【星海出品】Calico研究汇总
Calico项目由Tigera公司发起并主导开发 源码 https://github.com/projectcalico/calico?tabreadme-ov-file#-join-the-calico-community 简介 Tigera是一家专注于云原生安全的公司,于2016年成立,其核心产品包括开源的Calico项目以及商业版的Calico Ent…...
观成科技:摩诃草组织Spyder下载器流量特征分析
一、概述 自2023年以来,摩诃草组织频繁使用Spyder下载器下载远控木马,例如Remcos。观成安全研究团队对近几年的Spyder样本进行了深入研究,发现不同版本的样本在数据加密、流量模式等方面存在差异。基于此,我们对多个版本样本的通…...
中心极限定理(CLT)习题集 · 题目篇
中心极限定理(CLT)习题集 题目篇 共 18 题,覆盖经典 CLT、Lyapunov/Lindeberg 条件、Berry–Esseen 评估、 以及工程/数据科学应用与编程仿真。推荐先独立完成,再看《答案与解析篇》。 之前已经出过相关的知识点文章,…...
ITL和TTL线程间值的传递
InheritableThreadLocal InheritableThreadLocal 继承自 ThreadLocal,增加了父线程到子线程的值传递功能。当一个新线程被创建时,InheritableThreadLocal 会将父线程中 ThreadLocal 变量的值拷贝到子线程(浅拷贝),子线…...
Android学习总结之Room篇
一、Room 框架基础 1. 实体类(Entity) 实体类用于描述数据库表的结构。通过使用 Entity 注解,可以将一个 Java 类映射到数据库中的一张表。例如,以下是一个简单的 User 实体类: import androidx.room.Entity; impor…...
java IO流
一:概述 (1)IO (2)流 二:分类 (1)流向 (2)数据单位 (3)IO流角色 三:API (1)InputStream ÿ…...
STM32 串口USART
目录 常见的通信方式 串行通信和并行通信 全双工,半双工和单工通信 同步通信和异步通信 通信速率 常见的通信协议 串口基础知识 电平特性 串口传输协议 STM32F103的USART资源 端口引脚 数据寄存器单元 发送接收控制单元 实现串口发送 printf…...
数字IC后端项目典型问题之后端实战项目问题记录(2025.04.24)
今天给大家分享下近两天小编帮助学员解决的几个经典后端项目问题。希望能够对大家的学习和工作有所帮助。 Q1:在做a7top顶层物理验证Calibre LVS检查时提示NOT COMPARED,请问是什么原因? 我们在用calibre检查LVS后,其结果基本上就是以下三种…...
关于边缘计算盒子的外部接口保护
边缘计算盒子是一种基于边缘计算和人工智能技术的智能设备,它内置了灵活可配的多样化AI算法库,所以也被称为AI算法盒子或智能边缘分析一体机,可以将数据处理和分析的能力推至离数据源最近的边缘位置,提供高效的数据处理和实时响应…...
OCP考试需要注意什么?
一、OCP考试需要准备的资料 身份证件:携带有效的身份证件(如身份证、护照等),以便在考试当天进行身份验证。确保身份证件在考试当天仍然有效,并且与报名时使用的证件一致。 准考证:打印并携带准考证&…...
git Http改用户下载
用原先别人账号,无权下更新 http方式设置自己账号 例如 git fetch --all 提示没有权限从 http://192.168.1.2/gitlab/项目路径.git下载 git remote set-url origin http://your-username192.168.1.2/gitlab/项目路径.git your-username修改成自己的git账号 需要输入一个Tok…...
postgres 导出导入(基于数据库,模式,表)
在 PostgreSQL 中,导出和导入数据库、模式(schema)或表的数据可以使用多种工具和方法。以下是常用的命令和步骤,分别介绍如何导出和导入整个数据库、特定的模式以及单个表的数据。 一、导出数据 1. 使用 pg_dump 导出整个数据库…...
把dll模块注入到游戏进程的方法_挂起进程注入
一. 概述 挂起进程注入是指在创建进程的时候把运行状态设置为挂起,然后创建一个远程线程,来注入。挂起进程注入作为远线程注入的一个补充,可以在进程创建的时候就注入,从而注入时间较早,不宜被拦截。易知挂起进程注入的局限性也就是如果进程已经启动,那么这种注入方式就…...
TypeScript 开发实战:如何安全替换字符串中的关键字
在 TypeScript 开发中,我们经常需要处理字符串替换的场景。最近我在开发一个表达式解析功能时,遇到了一个有趣的挑战:如何将用户输入的简化数学表达式(如"sin")替换为标准形式(如"Math.sin&…...
ES6 模块化 与 CommonJS 的核心概念解析
以下是关于 ES6 模块化 与 CommonJS 的核心概念解析、知识点总结及使用场景说明: 1. ES6 模块化与 CommonJS 是什么? ES6 模块化(ECMAScript Modules, ESM) 定义:ES6 标准引入的模块系统,使用 import 和 …...
【踩坑记录】stm32 jlink程序烧录不进去
最近通过Jlink给STM32烧写程序时一直报错,但是换一个其他工程就可以烧录,对比了一下jink配置,发现是速率选太高了“SW Device”,将烧录速率调整到10MHz以下就可以了...
CS144 Lab 6 实战记录:构建 IP 路由器
1 实验背景与目标 在 CS144 的 Lab 6 中,我们需要在之前实现的 NetworkInterface(Lab 5)基础上构建一个完整的 IP 路由器。路由器的主要任务是根据路由表将接收到的 IP 数据报转发到正确的网络接口,并发送给正确的下一跳…...
AI与智能能源管理:如何通过AI优化能源分配和消耗?
引言:能源管理面临的新挑战 在“双碳”目标持续推进的背景下,能源管理已经不再是简单的节电节水问题,而是关乎可持续发展和企业长期竞争力的核心议题。无论是工业园区、写字楼,还是家庭用户,能源的使用正在变得越来越复…...
【蓝桥杯】产值调整
产值调整 题目描述 偏远的小镇上,三兄弟共同经营着一家小型矿业公司“兄弟矿业”。公司旗下有三座矿山:金矿、银矿和铜矿,它们的初始产值分别用非负整数 A A A、 B B B 和 C C C 表示。这些矿山的产出是小镇经济的核心,支撑着…...
使用Next.js构建单页面React应用
最近遇到一个问题 突然要一个单页面的项目 用惯了Next.js 而 create-react-app 又不推荐且不灵活 最终找发现Nextjs也支持单页面应用 以下是使用Next.js构建单页面React应用过程 1 正常创建项目 (我选择的是Pages Router 而非 AppRoute) 2 修改配置文件 next.config.ts impor…...
Python字符串三剑客:len()、split()、join()深度解析
目录 一、len():字符串的"测谎仪" 二、split():字符串的"解剖刀" 参数解析: 实战场景: 三、join():字符串的"缝合怪" 性能优势: 实战案例: 高级技巧&…...
大模型是如何生成内容的?
大模型(如 GPT、Claude、LLaMA 等)生成内容的过程,其实就是一个 逐词预测上下文推理 的过程。我们可以把它想象成一个“超级自完成引擎”:每一步都在问自己—— “在目前上下文下,最合理的下一个词是什么?”…...
Python元组全面解析:从基础到高级应用指南
一、元组基础概念与核心特性 1.1 元组的本质定义 元组(Tuple)是Python中重要的不可变序列类型,由多个元素组成的有序集合。其核心特性表现在: 元素按插入顺序存储,支持索引访问所有元素存储在连续内存空间ÿ…...
Docker部署DeepSeek常见问题及解决方案
在使用Docker部署DeepSeek的过程中,许多开发者可能会遇到一些常见问题。本文整理了几个高频问题及其解决方案,帮助大家更顺利地完成部署。 镜像拉取失败 问题现象 执行 docker pull 命令时,提示超时或镜像不存在。 可能原因 1. 网络环境不稳定,导致连接Docker Hub失败…...
身份证实名认证接口数字时代的信任基石-node.js实名认证集成
在互联网深度渗透生活的当下,从线上购物、社交娱乐到金融理财、政务办理,每一次指尖的触碰都在虚拟世界中留下痕迹。身份证实名认证作为连接现实身份与网络身份的桥梁,正以其不可替代的作用,重塑着数字时代的信任体系。它不仅是保…...
多维时序 | LightGBM多变量时序预测(Matlab完整源码和数据,适合基础小白研究)
多维时序 | LightGBM多变量时序预测(Matlab完整源码和数据,适合基础小白研究) 目录 多维时序 | LightGBM多变量时序预测(Matlab完整源码和数据,适合基础小白研究)效果一览基本介绍程序设计参考资料 效果一览…...
强化学习(Reinforcement Learning, RL)和深度学习(Deep Learning, DL)
强化学习(Reinforcement Learning, RL)和深度学习(Deep Learning, DL)是人工智能领域两个重要的研究方向,虽然二者可以结合(如深度强化学习),但其核心思想、目标和应用场景存在本质区…...
图论---Prim堆优化(稀疏图)
题目通常会提示数据范围: 若 V ≤ 500,两种方法均可(朴素Prim更稳)。 若 V ≤ 1e5,必须用优先队列Prim vector 存图。 #include <iostream> #include <vector> #include <queue> #include <…...
【优秀三方库研读】【C++基础知识】odygrd/quill -- 折叠表达式
compute_encoded_size_and_cache_string_lengths 方法中这段代码是一个C的折叠表达式(fold expression)的应用,用于计算多个参数编码后的总大小。下面我将详细解释这段代码的每个部分,并说明为什么这样写。 代码如下: …...
优化Nginx的下载功能
缘起: 我购置了一台阿里云ECS,其EIP带宽3m/s,但是在其上的作为下载文件的服务器nginx提供的下载速度仅有几百KB。 分析: 既然没有达到带宽瓶颈,肯定存在优化的空间。浮现脑海的想法,nginx没有进行最佳配置…...