Golang单元测试
文章目录
- 传统测试方法
- 基本介绍
- 主要缺点
- 单元测试
- 基本介绍
- 测试函数
- 基准测试
- 示例函数
传统测试方法
基本介绍
基本介绍
- 代码测试是软件开发中的一项重要实践,用于验证代码的正确性、可靠性和预期行为。通过代码测试,开发者可以发现和修复潜在的错误、确保代码按预期工作,并提高系统的质量和稳定性。
- 单元测试是针对代码中最小的可测试单元(如函数、方法或类)进行的测试,以验证代码单元在给定输入下的行为是否正确。单元测试通常由开发者编写,并使用特定的测试框架和断言库来定义测试用例、执行测试代码,并验证测试结果。
例如,现在要求对cal.go文件中的函数进行代码测试。cal文件中的代码如下:
package calfunc Add(num1 float64, num2 float64) float64 {return num1 + num2
}func Sub(num1 float64, num2 float64) float64 {return num1 + num2 // 代码错误
}func Mul(num1 float64, num2 float64) float64 {return num1 * num2
}func Div(num1 float64, num2 float64) float64 {return num1 * num2 // 代码错误
}
常见的测试方法是将测试代码直接写到main函数中,或在main函数中调用对应的测试函数。如下:
package mainimport ("fmt""go_code/UnitTest/cal"
)func main() {if ret := cal.Add(10, 20); ret != 30 {fmt.Printf("error: cal.Add(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 30.0)}if ret := cal.Sub(10, 20); ret != -10 {fmt.Printf("error: cal.Sub(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, -10.0)}if ret := cal.Mul(10, 20); ret != 200 {fmt.Printf("error: cal.Mul(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 200.0)}if ret := cal.Div(10, 20); ret != 0.5 {fmt.Printf("error: cal.Div(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 0.5)}
}
运行程序后可以得到代码的测试结果。如下:

主要缺点
主要缺点
将测试代码写到main函数中,主要存在如下缺点:
- 难以维护和扩展:测试代码与程序代码耦合在一起,每次完成代码测试后都需要恢复程序代码,并且每次新增测试函数时都需要手动在main函数中新增调用逻辑。
- 缺乏测试框架支持:传统的测试方法通常缺乏成熟的测试框架支持,无法提供丰富的断言函数、测试报告等功能,这使得测试编写和执行过程相对繁琐,并缺乏对测试结构体的全面分析。
单元测试
基本介绍
基本介绍
- Go语言中自带一个轻量级的测试框架testing,其功能被封装到了标准库的testing包中,结合
go test命令可以方便地进行单元测试和性能测试。 - 在Go中,每个源文件的测试代码都单独写到一个对应的测试文件中,测试文件名必须以
_test.go为后缀,并将其与被测试文件放在同一个目录下,比如要对cal.go文件进行测试,测试文件通常命名为cal_test.go,并将其放在cal.go所在的目录下。 - 在测试文件中由三种类型的函数:测试函数、基准测试函数、示例函数,
go test命令会遍历所有测试文件中的这些函数,生成一个临时的main包用于调用相应的测试函数,接着构建并运行、报告测试结果,最后清理测试中生成的临时文件。
说明一下: 文件名以_test.go为后缀的测试函数,在执行go build时不会被构建成包的一部分。
测试函数
测试函数
- 在Go中,测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头,通常测试函数命名为
Test+被测函数名,比如测试Add函数的测试函数命名为TestAdd。
测试函数的签名要求如下:

T是testing包中的一个结构体类型,用于表示测试状态和提供测试功能。其常用方法如下:
| 方法名 | 功能 |
|---|---|
| Log | 采用与fmt.Println相同的格式化语法输出日志信息 |
| Logf | 采用与fmt.Printf相同的格式化语法输出日志信息 |
| Fail | 将当前测试标记为失败,但仍继续执行该测试 |
| FailNow | 将当前测试标记为失败,并停止执行该测试 |
| Error | 输出错误信息,并将当前测试标记为失败(相当于调用Log之后调用Fail) |
| Errorf | 格式化输出错误信息,并将当前测试标记为失败(相当于调用Logf之后调用Fail) |
| Fatal | 输出致命错误信息,并将当前测试标记为失败(相当于调用Log之后调用FailNow) |
| Fatalf | 格式化输出致命错误信息,并将当前测试标记为失败(相当于调用Log之后调用FailNow) |
| SkipNow | 将当前测试标记为跳过,并停止执行该测试 |
| Skip | 输出跳过信息,并将当前测试标记为跳过(相当于调用Log之后调用SkipNow) |
说明一下:
- 这里所说的“当前测试”指的是“当前testing测试框架正在执行的测试函数”,“将当前测试标记为失败”指的是“将当前正在执行的测试函数标记为失败”,“停止执行当前测试”指的是“停止当前正在执行的测试函数,继续执行下一个测试函数”。
- 当一个测试被标记为跳过时,如果该测试在此之前已经被标记为失败,那么该测试最终会被判定为FAIL而不是SKIP。
- SkipNow、Skip和FailNow必须在运行测试的go协程中进行调用,而不能在测试期间创建的go协程中调用,因为SkipNow、Skip和FailNow不会导致其他go协程停止(go协程在后续博客中讲解)。
测试函数案例
比如我们要对之前cal.go文件中的函数进行代码测试,则在cal.go文件所在目录下建立名为cal_test.go的测试文件,并在测试文件中编写对应的测试函数。如下:
package calimport ("testing"
)func TestAdd(t *testing.T) {if ret := Add(10, 20); ret != 30 {t.Errorf("cal.Add(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 30.0)}
}func TestSub(t *testing.T) {if ret := Sub(10, 20); ret != -10 {t.Errorf("cal.Sub(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, -10.0)}
}func TestMul(t *testing.T) {if ret := Mul(10, 20); ret != 200 {t.Errorf("cal.Mul(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 200.0)}
}func TestDiv(t *testing.T) {if ret := Div(10, 20); ret != 0.5 {t.Errorf("cal.Div(%.2f, %.2f) = %.2f, want %.2f\n", 10.0, 20.0, ret, 0.5)}
}
在测试文件所在目录执行go test命令,它会在当前目录中查找所有的测试文件,逐个执行测试文件中的测试函数并输出测试结果,包括各个测试函数的测试状态、日志信息、运行时间等。如下:

在任意目录下通过go test 包路径的方式,可以查找指定包路径下的测试文件并执行其测试函数。如下:

说明一下: 只要本次测试中有一个测试函数的测试状态为FAIL,那么本次测试的状态即为FAIL。
显示详细的测试信息
go test命令默认只会输出测试状态为FAIL的测试函数信息,通过携带-v参数可以查看更详细测试信息。如下:

测试指定的测试文件
go test命令默认会执行当前目录下所有测试文件中的测试函数,如果只想执行某个或某几个测试文件中的测试函数,可以在go test命令后指明对应的测试文件名,同时需要指明与测试文件相关的go源文件。如下:

测试指定的测试函数
go test命令默认会执行测试文件中所有的测试函数,通过携带-run参数可以只执行指定的测试函数。如下:

说明一下: go test命令的-run参数可以接受一个正则表达式,它将执行所有与该正则表达式匹配的测试函数。
测试覆盖率
通过携带-cover参数可以查看本次测试的测试覆盖率,即在本次测试中被测试代码至少被运行一次的代码占总代码数的比例。如下:

基准测试
基准测试函数
- 基准测试(Benchmarking)是一种在计算机编程中用于评估程序性能的技术,其目的是测量代码在给定工作负载下的性能指标,如执行时间、内存消耗等。通过基准测试可以对不同实现方式或优化策略之间的性能差异进行比较和评估,这对于优化程序、找出性能瓶颈以及进行系统比较和选型非常有用。
- 在Go中,基准测试函数的名字必须以Benchmark开头,可选的后缀名必须以大写字母开头,通常基准测试函数命名为
Benchmark+被测函数名,比如测试Add函数的基准测试函数命名为BenchmarkAdd。
基准测试函数的签名要求如下:

B是testing包中的一个结构体类型,用于控制和测量基准测试的执行。其常用方法如下:
| 方法名 | 功能 |
|---|---|
| ResetTimer | 重置基准测试的计时器 |
| StartTimer | 启动基准测试的计时器 |
| StopTimer | 停止基准测试的计时器 |
基准测试函数案例
比如我们要对之前cal.go文件中的各个函数进行基准测试,则在cal_test.go文件中增加对应的基准测试函数即可。如下:
func BenchmarkAdd(b *testing.B) {for i := 0; i < b.N; i++ {Add(10, 20)}
}func BenchmarkSub(b *testing.B) {for i := 0; i < b.N; i++ {Sub(10, 20)}
}func BenchmarkMul(b *testing.B) {for i := 0; i < b.N; i++ {Mul(10, 20)}
}func BenchmarkDiv(b *testing.B) {for i := 0; i < b.N; i++ {Div(10, 20)}
}
go test命令默认只会运行普通的测试函数,通过携带-bench参数可以指定要运行的基准测试函数。如下:

基准测试结果说明:
- 第一列:BenchmarkXxx表示基准测试函数的名称,后面的数字表示运行基准测试函数时的GOMAXPROCS的值。
- 第二列:基准测试函数的执行次数。
- 第三列:每执行一次基准测试函数的平均耗时(ns/op)。
- 第四列:每执行一次基准测试函数的平均内存分配的总字节数(B/op)。
- 第五列:每执行一次基准测试函数的平均内存分配次数(allocs/op)。
基准测试函数的运行机制:
- testing测试框架为了保证测试结果的稳定性和准确性,在B类型中设置了字段N,在基准函数中可以通过b.N指定操作执行的循环次数。测试框架会自动调整b.N的值,确保每个基准测试函数运行至少达到1秒钟,然后再计算出平均每执行一次操作所需的时间。
- 由于基准测试驱动器开始时并不知道运行每个基准测试函数所需花费的时间,因此在真正运行每一个基准测试函数之前,基准测试驱动器会先尝试将b.N设置为一个较小的值,如果基准测试函数的运行时间小于1秒,则加大b.N的值,直到基准测试函数的运行时间至少达到1秒钟。
- 经过验证,在本人的机器上b.N的初始值为1,尝试执行基准测试函数后根据计时器的值判断下一次尝试的b.N值,但下一次尝试的b.N值最多为上一次b.N值的100倍,并且b.N的上限为1000000000,当b.N的值达到上限后,即使基准测试函数的运行时间没有达到1秒,也不再增加b.N的值。
说明一下:
- 使用
go test命令运行基准测试函数时仍然会运行普通的测试函数,如果普通的测试函数中存在测试状态为FAIL的测试函数,那么将不会运行基准测试函数。因此在运行基准测试函数之前请保证所有普通的测试函数能正确通过测试,或将-run参数设置为none表示不运行任何普通测试函数。 - 将
-bench参数指定为.表示运行所有的基准测试函数,也可以将其指定为一个正则表达式,它将执行所有与该正则表达式匹配的基准测试函数。 go test命令的-benchmem参数,用于在运行基准测试函数时报告内存分配的统计信息,包括内存分配次数和内存分配的总字节数,否则基准测试只有前三列结果。
重置计时器
如果基准测试函数中存在一些数据准备工作,并且你不希望这部分工作的时间被计时器统计,则可以在数据准备完毕后,通过调用B类型的ResetTimer方法重置计时器。如下:
func BenchmarkDemo(b *testing.B) {// 基准测试数据准备工作...b.ResetTimer() // 重置计时器// [计时区域]}
说明一下: 计时器会在基准测试函数调用时自动启动,并在函数执行完毕后自动停止。
指定区域计时
在基准测试函数中,如果你希望统计某些非连续区域的耗时,则可以通过调用B类型的StartTimer和StopTimer方法手动启动或停止计时器。如下:
func BenchmarkDemo(b *testing.B) {// 其他工作1...b.ResetTimer() // 重置计时器// [计时区域1]b.StopTimer() // 停止计时器// 其他工作2...b.StartTimer() // 启动计时器// [计时区域2]b.StopTimer() // 停止计时器// 其他工作3...
}
注意: 为了避免统计其他工作1...的耗时,需要在[计时区域1]之前调用ResetTimer方法而不是StartTimer方法。
指定基准测试运行时间
通过go test命令的-benchtime参数,可以指定每个基准测试函数至少需要达到的运行时间。如下:

注意: 如果基准测试函数的b.N值达到上限后仍无法达到所指定的运行时间,那么b.N的值也不会继续增加。
指定操作迭代次数
通过go test命令的-benchtime参数,也可以指定每个基准测试函数中操作的迭代次数,即b.N的值。如下:

指定基准测试可用cpu数
通过go test命令的-cpu参数,可以指定运行基准测试时调度器可使用的最大CPU核心数。如下:

性能分析
通过go test命令的-cpuprofile和-memprofile参数,可以分别生成CPU分析文件和内存分析文件。如下:

pprof是Go语言中自带的性能分析工具,通过go tool pprof 分析文件 命令即可对指定的分析文件进行解析。以内存性能分析为例,执行go tool pprof mem.out命令后会出现pprof的交互式命令行,在命令行中输入top命令可以查看耗费内存资源最多的函数。如下:

pprof工具分析结果说明:
- flat:在该函数上直接花费的时间或资源总量(比如CPU时间、内存资源等),不包括该函数调用的其他函数所花费的时间或资源。
- flat%:flat值占分析总量的百分比,表示该函数直接花费的时间或资源占资源使用的百分比。
- sum%:这个百分比是累积的,表示到当前行为止所有函数的flat%的总和。
- cum:该函数及其调用的所有函数总共花费的时间或资源总量。
- cum%:cum值占分析总量的百分比,表示该函数及其调用的所有函数花费的时间或资源占资源使用的百分比。
小贴士:如果一个函数的flat%值高,则表明该函数本身可能是性能瓶颈,而如果一个函数的cum%值高,则表明该函数调用链上的某个函数可能存在性能瓶颈。
此外,在pprof的交互式命令行中输入web命令,可以生成调用链路图,在链路图中会展示对应资源的耗费情况。如下:

说明一下:
- pprof工具的调用链路图显示功能需要安装Graphviz工具,可以在Graphviz官网进行下载,安装并设置PATH环境变量后,即可在pprof的交互式命令行中执行web命令生成调用链路图。
示例函数
示例函数
- 示例函数是一种用于演示和测试包的功能的特殊函数,其主要目的是提供关于如何使用包中的功能的示例代码以及相应的预期输出,这些示例函数可以作为文档的一部分,帮助其他开发人员理解和学习如何正确使用包中的函数、结构和类型。
- 在Go中,示例函数没有参数和返回值,其名字必须以Example开头,可选的后缀名必须以大写字母开头,通常示例函数命名为
Example+对应函数名,比如Add函数的示例函数命名为ExampleAdd。 - 通过
go test命令运行测试时示例函数也会被执行,如果示例函数内有类似// Output:格式的注释,那么测试工具就会执行这个示例函数,并检查示例函数的标准输出与注释是否匹配,如果匹配则测试通过,否则测试失败。
示例函数案例
比如我们要演示之前cal.go文件中的各个函数的使用,则在cal_test.go文件中增加对应的示例函数即可。如下:
func ExampleAdd() {ret := Add(10, 20)fmt.Println(ret)// Output: 30
}func ExampleSub() {ret := Sub(10, 20)fmt.Println(ret)// Output: -10
}func ExampleMul() {ret := Mul(10, 20)fmt.Println(ret)// Output: 200
}func ExampleDiv() {ret := Div(10, 20)fmt.Println(ret)// Output: 0.5
}
运行go test命令后可以看到所有测试函数和示例函数均被执行。如下:

如果某个示例函数的// Output:注释中的内容,与实际执行示例函数时的输出不匹配,则该示例函数被标记为失败,从而导致整个测试失败。如下:

相关文章:
Golang单元测试
文章目录 传统测试方法基本介绍主要缺点 单元测试基本介绍测试函数基准测试示例函数 传统测试方法 基本介绍 基本介绍 代码测试是软件开发中的一项重要实践,用于验证代码的正确性、可靠性和预期行为。通过代码测试,开发者可以发现和修复潜在的错误、确保…...
mac下安装airflow
背景:因为用的是Mac的M芯片的电脑,安装很多东西都经常报错,最近在研究怎么把大数据集群上的crontab下的任务都配置到一个可视化工具中,发现airflow好像是个不错的选择,然后就研究怎么先安装使用起来,后面再…...
二进制中1的个数c++
题目描述 计算鸭给定一个十进制非负整数 NN,求其对应 22 进制数中 11 的个数。 输入 输入包含一行,包含一个非负整数 NN。(N < 10^9) 输出 输出一行,包含一个整数,表示 NN 的 22 进制表示中 11 的个数。 样例输入 100 …...
【面试干货】数据库乐观锁,悲观锁的区别,怎么实现
【面试干货】数据库乐观锁,悲观锁的区别,怎么实现 1、乐观锁,悲观锁的区别2、总结 💖The Begin💖点点关注,收藏不迷路💖 1、乐观锁,悲观锁的区别 悲观锁(Pessimistic Lo…...
移动端仪表盘,支持更多组件
05/22 主要更新模块概览 定位函数 快捷筛选 轨迹图表 时间组件 01 表单管理 1.1 【表单组件】- 表单关联新增支持自定义按钮样式 说明: 表单关联-关联数据按钮,原仅支持默认按钮样式,现增加关联数据按钮自定义功能,满…...
科技产业园3D探秘:未来科技之城的奇幻之旅
在数字时代的浪潮中,科技产业园区成为了推动城市经济发展、科技创新的重要引擎。 当我们打开科技产业园的3D可视化模型,仿佛穿越时空,来到了一个充满奇幻色彩的科技世界。在这里,高楼大厦鳞次栉比,绿色植被点缀其间&am…...
【Python搞定车载自动化测试】——Python基于Pytest框架实现UDS诊断自动化(含Python源码)
系列文章目录 【Python搞定车载自动化测试】系列文章目录汇总 文章目录 系列文章目录💯💯💯 前言💯💯💯一、环境搭建1.软件环境2.硬件环境 二、目录结构三、源码展示1.诊断基础函数方法2.诊断业务函数方法…...
探索SPI单线传输模式中时钟线与数据传输的简化
探索SPI单线传输模式:时钟线与数据传输的简化之道 在当今的嵌入式系统和微控制器通信中,串行外设接口(SPI)因其高速、全双工和同步的特点而广受欢迎。然而,随着设备尺寸和复杂性的不断减少,对SPI通信的简化…...
使用FFmpeg推流实现在B站24小时点歌直播
使用FFmpeg推流实现在B站24小时点歌直播 本文首发于个人博客 安装FFmpeg centos7 https://www.myfreax.com/how-to-install-ffmpeg-on-centos-7/ https://linuxize.com/post/how-to-install-ffmpeg-on-centos-7/ 使用FFmpeg在B站直播 https://zhuanlan.zhihu.com/p/2395…...
汽车防抱死制动系统ABS的单片机程序Proteus仿真设计
次设计对汽车防抱死系统进行简单的设计,针对车速、轮速两个信号进行分析,并根据最佳滑移率计算。采用对比实时滑移率对比分析,ECU控制制动器进行制动力调节使滑移率在制动过程处于最佳范围,保证系统具有良好制动性能。 汽车的制动液压调节器主要包含以下几个部件:调压电磁…...
IOS开发者证书快捷申请
App Uploader 在进行iOS应用开发中,可以借助appuploader辅助工具进行证书制作、上传和安装测试等操作。首先,您需要访问官方网站获取最新版本的appuploader。最新版本已经优化了与Apple账号的登录流程,无需支付688元,并提供了Windows版和Mac版供用户选择。下载完成后,解压…...
python 火焰检测
在日常生活,总是离不开火,有时候我们需要预防火灾发生,但是我们又不可能一直盯着,这时候我们就需要一款程序帮我们盯着,一旦发生火灾从而告知我们,今天就带大家编写这么一款应用。 安装需要的库 pip install opencv-python 代码实现 import cv2 # Library for…...
栈——顺序存储
#include<stdio.h> #define MaxSize 10 //栈的所有操作时间复杂度都是O(1) //定义 typedef struct{int data[MaxSize];int top; //栈顶指针,永远指向栈顶元素 }SqStack;//初始化,使栈顶指针指向-1 void InitStack(SqStack &S){S.top-1; }…...
军队仓库管理系统|DW-S301系统特点
部队仓库管理系统DW-S301系统通过数据采集、互联网和物联网技术,实现数字化智能管控,以提高军用物资的仓储准确率和流转率,缩短周转时间,降低库存成本,也有助于消除生产过程中的不确定性。 系统功能:通过部…...
MySQL和MongoDB数据库的区别
MySQL和MongoDB数据库的区别 随着大数据和云计算技术的兴起,数据库的选择成为开发者和架构师必须面对的重要决策。MySQL和MongoDB作为关系型数据库和非关系型数据库的代表,在各自领域都有着广泛的应用。本文将从多方面详细比较MySQL和MongoDB࿰…...
类脑计算和量子计算、人工智能的关系
According to www.iAsk.ai Ask Ai Search Engine: 类脑计算、量子计算和人工智能是三个不同但相关的领域。它们在不同层面上探索和利用了不同的计算模型和技术,但都旨在推动计算能力的发展和创新。 类脑计算是一种受到人脑神经系统启发的计算模型。它试图通过模拟…...
Qt5 互动地图,实现无人机地面站效果
一、概述 本文主要通过Qt5opmapcontrol实现一个简单的无人机地面站效果。opmapcontrol是一个比较古老的QT开源地面站库,可选择谷歌地图,必应地图, 雅虎地图,GIS等。可直接使用源码,也可以编译生成库进行调用。实现效果…...
【文末附gpt升级方案】TikTok Symphony AI套件:智能视频制作的新篇章
TikTok Symphony AI套件:智能视频制作的新篇章 摘要 随着短视频平台的兴起,视频内容的创作与制作已成为品牌方吸引用户、传递信息的重要手段。TikTok作为全球领先的短视频平台,近日宣布推出Symphony AI套件,旨在通过人工智能技术…...
面试回答——有高并发、高性能、高可用系统架构设计实践以及性能调优经验
🌈hello,你好鸭,我是Ethan,一名不断学习的码农,很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 🏃人生之义,在于追求,不在成败,勤通…...
rocketmq初识
package com.ldj.rocketmq.producer;import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message;import java.nio.charset.StandardCharsets;/*** User: ldj* Date: 2024/3/26* Time: 2:26* Description: 单向消息生产…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
