利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置
文章目录
- 前言
- 一、prometheus发现方式
- 二、监控指标注册架构图
- 三、部分代码展示
- 1.核心思想
- 2.代码目录
- 3、程序入口函数剖析
- 4、settings配置文件
- 5、初始化配置文件及consul
- 6、全局变量
- 7、配置config
- 8、公共方法目录common
- 9、工具目录tools
- 10、service层展示
- 11、命令行参数
- 12、Makefile示例
- 13、脚本示例
- 四、演示效果
- 1、上传代码,并整理xlsx文件
- 2、脚本执行命令
- 2.1 创建go.mod文件并下载标准库
- 2.2 执行构建命令
- 2.3 执行xlsx文件解析为json文件命令
- 2.4 执行获取json文件内容并注册到命令
- 2.5 验证
- 2.6 扩展情况说明
- 总结
前言
在实际产生环境中主要以prometheus监控为主,在使用该监控时,有个很大的问题时,需要手动修改Prometheus.yml文件,将监控指标手动添加进去,当监控指标少的时候,维护和添加都很方便,但是当一套环境中监控指标多大几百个,添加工作繁琐,这时你会想到写个shell脚本,对多个监控指标进行添加,但是你有没有考虑过此时的prometheus.yaml文件的可维护性以及当添加的监控指标越来越多时,prometheus主机的cpu、内存也随之增长,这时你该怎么处理呢?因此,本篇文章带你解决此类问题,准备好开始发车了!!!
一、prometheus发现方式
prometheus主要有以下几种发现方式:1)static_configs: #静态服务发现2)file_sd_configs: #文件服务发现3)dns_sd_configs: DNS #服务发现4)kubernetes_sd_configs: #Kubernetes 服务发现5)consul_sd_configs: Consul #consul服务发现
二、监控指标注册架构图

三、部分代码展示
1.核心思想
1、本代码主要是使用golang、xlsx文件、consul三大部分将整理好的监控指标(主机监控、微服务端口监控、业务接口监控、telegraf组件监控等及部分)通过golang调用consulApi注册到consul中2、xlsx文件中的sheet页必须满足settings.yaml文件中的这部分sheet_name:- "hosts_data"- "service_data"- "serviceurl_data"或者自行定义sheet页名称,同时一定要修改settings.yaml文件中的上述部分,二者必须保持一致3、代码的主要功能就是将整理好的xlsx文件,通过`tools.ProcessExcelFiles(cmdFlags)` 函数将xlsx形式中的文件转换为以json结尾的文件,具体的转换过程看代码即可4、注册到consul时,首先通过json反序列化操作,拿到对应的json数据值,然后对注册到consul中的五大部分(主机、主机探活、业务接口、微服务端口监控、agent组件监控)分别进行相关拼接操作5、当拼接操作结束后,调用tools目录下的函数,并传参,实际tools目录下的函数都是调用了consulAPI进行的注册6、makefile定义了代码的多重操作,但是执行繁琐,因此引入了launch.sh脚本,执行launch.sh xx 即可完成xlsx文件转换、注册功能等
2.代码目录
采用Makefile和launch.sh脚本做到执行代码命令的统一管理

3、程序入口函数剖析
cmd/main.go文件主要是代码的执行入口处,包含配置文件的解析、命令行参数解析、consul初始化、代码的执行入口
package mainimport ("log""import_consul/core"myflags "import_consul/flag""import_consul/global""import_consul/service""import_consul/tools"
)func main() {// 解析命令行参数cmdFlags := myflags.Parse()//读取配置文件core.InitConf()// 初始化Consulif consulClient, err := core.ConsulConnect(); err != nil {log.Fatalf("consul connect failed: %v", err)return} else {// 将初始化的客户端实例赋值给global.ConsulClient,以便全局使用global.ConsulClient = consulClientlog.Println("consul connect success")}//执行execl转json文件tools.ProcessExcelFiles(cmdFlags)//其余代码不在展示~~~~
}
4、settings配置文件
consul:ip: "xx" #conusl主机ipport: xx #consul端口service_name: #consul-web界面中的service目录名- "Host_Status"- "ICMP"- "Telegraf"- "Service_TCP"- "Service_URL"xlsx:xlsxfile_path: "/root/test.xlsx" #xlsx监控指标文件位置sheet_name: #xlsx文件中的sheet页名称- "hostinfo"- "serviceinfo"- "serviceurlInfo"jsonfile: #xlsx文件转为json文件后的保存位置hostjson_path: "/root/jsonfile/host.json" servicejson_path: "/root/jsonfile/service.json"serviceurljson_path: "/root/jsonfile/serviceUrl.json"
5、初始化配置文件及consul
初始化settings.yaml配置文件,主要使用golang的gopkg.in/yaml.v2 标准库,指定yaml文件位置并读取yaml文件进行反序列操作
package coreimport ("log""os""path/filepath""import_consul/config""import_consul/global""gopkg.in/yaml.v2"
)func InitConf() {// 直接构建配置文件的路径ConfigFile := filepath.Join("settings.yaml")c := &config.Config{}yamlConf, err := os.ReadFile(ConfigFile)if err != nil {log.Fatalf("get yamlconf error: %s", err)}err = yaml.Unmarshal(yamlConf, c) //yaml文件反序列化if err != nil {log.Fatalf("config init Unmarsharl: %v", err)}log.Print("config init Unmarsharl success")global.Config = c
}
初始化consul,主要使用github.com/hashicorp/consul/api consul的标准库,创建一个consul客户端对象
package coreimport ("import_consul/global""github.com/hashicorp/consul/api"
)// consul 初始化
func ConsulConnect() (*api.Client, error) {config := api.DefaultConfig()config.Address = global.Config.Consul.URL()if client, err := api.NewClient(config); err != nil {return nil, err} else {return client, nil}
}
6、全局变量
因为文件都已分层处理,为了方便程序间调用相应的文件,因此在此处将Config、consul客户端对象进行全局处理,使用时直接global.Config.xxx 或global.CounsulClient.xxx即可
package globalimport ("import_consul/config""github.com/hashicorp/consul/api"
)var (Config *config.Config //接收读取到的config文件ConsulClient *api.Client //consul客户端
)
7、配置config
主要是根据settings.yaml文件中定义的变量进行结构体配置,enter.go文件是config目录下结构体文件的总入口,与global中的全局变量Config遥相呼应
enter.gopackage config//配置入口初始化 采用结构体type Config struct {Consul Consul `yaml:"consul"`Xlsx Xlsx `yaml:"xlsx"`JsonFile JsonFile `yaml:"jsonfile"`}
consul.go
#consul结构体字段package configimport "fmt"//连接consul的ip、端口type Consul struct {IP string `yaml:"ip"`Port int `yaml:"port"`ServiceName []string `yaml:"service_name"`}func (c *Consul) URL() string {return fmt.Sprintf("%s:%d", c.IP, c.Port)}
其余的结构体不在展示,自行按照settings.yaml编写对应的struct结构体即可
8、公共方法目录common
此目录下的parse_xlsx_common.go文件主要是针对定义的sheet页来做相关操作,使用xlsx标准库获取到对应sheet页中的行、列数,然后循环获取每个表格中的数据,调用 writeJSONToFile()方法,将获取到的数据转换为json形式的文件并保存
package commonimport ("bufio""encoding/json""log""os""github.com/tealeg/xlsx/v3"
)// 处理hostinfo表格
func ParseHostInfo(sheet *xlsx.Sheet, fileName string) error {hostDist := make(map[string][]string)// 从第二行开始遍历(假设第一行是标题行)for rowNumber := 1; rowNumber < sheet.MaxRow; rowNumber++ {row, _ := sheet.Row(rowNumber)ip := row.GetCell(0).String()env := row.GetCell(1).String()hostType := row.GetCell(2).String()productInfo := row.GetCell(3).String()hostDist[ip] = []string{env, hostType, productInfo}}// 将hostDist序列化为JSON并写入文件if err := writeJSONToFile(hostDist, fileName); err != nil {log.Fatalf("ParseHostInfo Failed to write JSON to file: %v", err)}log.Printf("ParseHostInfo Success to write JSON to file: %v", hostDist)return nil//其余代码不在展示~~~~
}
9、工具目录tools
这个目录下主要用于存放实现代码所需要的工具文件,例如:golang解析xlsx文件、读取json文件、创建目录文件、consul注册监控指标文件工具等,如下所示
golang解析xlsx文件
package toolsimport ("fmt""log""sync""import_consul/common"myflags "import_consul/flag""import_consul/global""github.com/tealeg/xlsx/v3"
)//定义xlsx转json所需要的结构体
type ExcelToJson struct {File *xlsx.FileSheet *xlsx.Sheet
}
//创建工厂函数,实例化结构体
func newExcelToJson(filePath, sheetName string) (*ExcelToJson, error) {file, err := xlsx.OpenFile(filePath)if err != nil {log.Fatalf("open xlsx file failed:%v\n", err)return nil, err}log.Printf("open xlsx file success:%s\n", filePath)sheet, ok := file.Sheet[sheetName]if !ok {return nil, fmt.Errorf("sheet %s not found", sheetName)}return &ExcelToJson{File: file, Sheet: sheet}, nil
}// 调用common包中的ParseHostInfo方法 将xlsx中的hostinfo页解析并存到host.json文件中
func (e *ExcelToJson) ParseXLSXHost() error {if err := EnsureDir(global.Config.JsonFile.Hostjson_Path); err != nil {return fmt.Errorf("failed to ensure directory for host json: %w", err)}return common.ParseHostInfo(e.Sheet, global.Config.JsonFile.Hostjson_Path)
}// 处理Execl文件的逻辑函数入口,使用协程和互斥锁,提高执行效率
var mutex sync.Mutex // 声明互斥锁
func ProcessExcelFiles(cmdFlags myflags.CmdFlags) {//创建匿名切片结构体并初始化sheetActions := []struct {Flag boolSheet stringAction func(*ExcelToJson) error}{{cmdFlags.ParseHost, global.Config.Xlsx.SheetName[0], (*ExcelToJson).ParseXLSXHost},}var wg sync.WaitGroup//定义保存error的管道errChan := make(chan error, len(sheetActions))for _, action := range sheetActions {if action.Flag {wg.Add(1)//开启协程go func(action struct {Flag boolSheet stringAction func(*ExcelToJson) error}) {defer wg.Done()e, err := newExcelToJson(global.Config.Xlsx.XlsxFile_Path, action.Sheet)if err != nil {log.Fatalf("实例化ExcelToJson结构体失败,%v\n", err)errChan <- errreturn}if err := action.Action(e); err != nil {errChan <- errreturn}// 示例:安全更新共享资源mutex.Lock() // 在访问共享资源前加锁mutex.Unlock() // 完成后解锁}(action)}}wg.Wait()close(errChan)//循环打印管道中的错误并输出for err := range errChan {if err != nil {log.Fatalf("Error processing sheet: %v", err)}}
}
//其余代码不在展示~~~~
此处更重要的是数据清洗转换,设置好指标注册到consul中Tag标签都展示什么,因为这关系到prometheus采集到数据后,在grafana中怎么对图形进行处理
监控指标向consul注册
package toolsimport ("log""import_consul/global""github.com/hashicorp/consul/api"
)func Add_host(ip, env, HostType, businesscode string) {// 构造服务注册的配置registration := &api.AgentServiceRegistration{ID: global.Config.Consul.ServiceName[0] + ip, // 唯一服务IDName: global.Config.Consul.ServiceName[0], // 服务名称Address: ip,Tags: []string{global.Config.Consul.ServiceName[0]},Meta: map[string]string{"ip": ip,"env": env,"type": HostType,"business_code": businesscode,},}// 调用Consul客户端及consul的注册服务函数Agent().ServiceRegister(registration)if err := global.ConsulClient.Agent().ServiceRegister(registration); err != nil {log.Fatalf("Error registering host with Consul:%v\n", err)return}log.Printf("Host %s registered successfully\n", ip)
}
//其余代码不在展示~~~~
当用上述代码对注册到consul中的相关标签进行清洗转换后,就如下图所示

10、service层展示
通过自定义类型HostInfo,调用tools目录中json文件处理函数ReadJSONFile(),对json文件进行处理,处理完成后,调用tools目录下的Add_host()函数,实现监控指标的注册
package serviceimport ("log""import_consul/global""import_consul/tools"
)// HostInfo 用于映射YAML文件结构
type HostInfo map[string][]string// Host 读取并解析host.yaml,然后添加每个主机
func Host() {var results HostInfoerr := tools.ReadJSONFile(global.Config.JsonFile.Hostjson_Path, &results)if err != nil {log.Fatalf("Error reading adn parsing JSON file: %s,error: %v\n", global.Config.JsonFile.Hostjson_Path, err)}log.Printf("Success reading and parsing JSON file: %s\n", global.Config.JsonFile.Hostjson_Path)for hostIP, info := range results {if len(info) >= 3 {tools.Add_host(hostIP, info[0], info[1], info[2])}}
}
//其余代码不在展示~~~~
11、命令行参数
因为有xlsx文件转换json文件的代码、各监控指标注册consul的代码,每次执行并不需要全部执行,因为引入命令行参数的标准库,想要执行哪些代码,直接编译程序代码,然后./xxx -parseHost=true即可执行对应的代码
package flagimport ("flag"
)// CmdFlags 用于保存命令行参数
type CmdFlags struct {ParseHost bool
}// Parse 解析命令行参数
func Parse() CmdFlags {var cmdFlags CmdFlags//只有parseHost=true时才会执行flag.BoolVar(&cmdFlags.ParseHost, "parseHost", false, "Parse hosts from XLSX and convert to YAML")flag.Parse()return cmdFlags
}
12、Makefile示例
# 定义变量
BINARY_NAME ?= default_app_name #如果BINARY_NAME没有在命令行中指定,则使用default_app_name为默认值GOBUILD=go build -o $(BINARY_NAME) ./cmd
GOCLEAN=go clean
GORUN=go run ./cmd/...
GOGET=go get
CMD=./$(BINARY_NAME)# 默认目标
all: build# 构建二进制文件
build:$(GOBUILD)# 清理构建文件
clean:$(GOCLEAN)rm -f $(BINARY_NAME)# 依赖获取,如果有外部依赖可以使用
#./...: 这是go get命令的参数,指示go get搜索当前目录(以及所有子目录)中的所有Go文件,并分析它们的导入声明
deps:$(GOGET) ./...# 根据需要执行的特定服务,可以添加更多的运行目标
run-execlTohostJson:$(CMD) -parseHost=truerun-execToAllJson:$(CMD) -parseHost=true -parseService=true -parseServiceURL=truerun-host:$(CMD) -registerHost=true//其余的不展示~~~
13、脚本示例
主要将makefile中的指令集中到脚本中,执行方便,不容易出错.前提是服务器必须提前安装好make gcc等基础命令
#!/bin/bash# 检查是否传递了参数
if [ "$#" -lt 1 ]; thenecho "Usage: $0 {build|clean|run|deps|run-execlTohostJson|...|run-all} [BINARY_NAME]"exit 1
fiACTION=$1
BINARY_NAME=${2:-} # 如果提供了第二个参数,使用它作为BINARY_NAME# 获取脚本所在的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"# 推断 Makefile 所在的目录(假设 Makefile 在脚本目录的上一级)
MAKEFILE_DIR="$(dirname "$SCRIPT_DIR")"# nohup.out 文件路径
NOHUP_FILE="$SCRIPT_DIR/nohup.out"# binary_name 文件路径,用于存储和读取 BINARY_NAME
BINARY_NAME_FILE="$SCRIPT_DIR/.binary_name"# 检查 nohup.out 文件是否存在,如果不存在则创建
if [ ! -f "$NOHUP_FILE" ]; thentouch "$NOHUP_FILE"
fi# 如果提供了 BINARY_NAME,则将其保存到文件中
if [ -n "$BINARY_NAME" ]; thenecho "$BINARY_NAME" > "$BINARY_NAME_FILE"
elif [ -f "$BINARY_NAME_FILE" ]; then# 如果没有提供 BINARY_NAME 但文件存在,则从文件中读取BINARY_NAME=$(cat "$BINARY_NAME_FILE")
fi# 根据参数执行相应的 make 命令
case "$ACTION" inbuild)echo "===== Starting $ACTION with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE";;clean)# 清理时,需要确保使用之前存储的 BINARY_NAMEif [ -n "$BINARY_NAME" ]; thenecho "===== Cleaning with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE"# 清理操作完成后,删除 BINARY_NAME 文件rm -f "$BINARY_NAME_FILE"elseecho "No BINARY_NAME specified or found. Please provide a binary name or run a build first."exit 1fi;;run|deps|run-execlTohostJson|run-registerServices|run-all)echo "===== Starting $ACTION with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE";;*)echo "Invalid option: $ACTION"echo "Usage: $0 {build|clean|run|deps|run-execlTohostJson|...|run-all} [BINARY_NAME]"exit 1;;
esac
四、演示效果
1、上传代码,并整理xlsx文件
1、上传代码至prometheus或与pormetheus机器相同的机器2、机器必须已安装golang环境 go>=1.18版本3、整理xlsx文件,xlsx模板如下截图所示



2、脚本执行命令
上传完代码后,cd /xxx/xxx/xxx/ 目录下
2.1 创建go.mod文件并下载标准库
[root@python2 import_consul]# go mod init import_consul
[root@python2 import_consul]# go mod tidy #下载依赖
2.2 执行构建命令
[root@python2 root]# cd scripts
[root@python2 scripts]# ./launch.sh build service_register_consul
2.3 执行xlsx文件解析为json文件命令
第一种: 只解析某一个sheet页[root@python2 scripts]# ./launch.sh run-execlTohostJson
第二种: 解析全部sheet页[root@python2 scripts]# ./launch.sh run-execlToALLJson
2.4 执行获取json文件内容并注册到命令
第一种: 只注册某个监控指标[root@python2 scripts]# ./launch.sh run-host
第二种: 注册全部指标[root@python2 scripts]# ./launch.sh run-registerServices
2.5 验证
1、查看scripts/nphup.out文件中命令执行是否有报错2、查看consul中是否已注册到指标


2.6 扩展情况说明
如下截图所示,显示服务健康检查失败,这是因为我在指标注册到consul的代码中配置了健康检查机制checks,又因为本地开发环境与预发环境的网段不通,所有才会导致健康检查失败,并不是代码是失败的。
指标注册到consul的代码的健康检查 部分代码示例:Check: &api.AgentServiceCheck{TTL: "10s", //心跳检测时间DeregisterCriticalServiceAfter: "5m", // 如果服务1分钟内处于critical状态,则自动注销},

至此,整个代码的演示也就完成了
总结
写这个代码的原因有两个,其一就是我刚开始所说的维护prometheus.yml文件的成本越来越高,且服务器资源日益不足;其二刚才最近在学习golang,也借此机会提高一下golang的基础语法知识以及标准库的使用方法。因此才有此代码的诞生.主要给大家一个思路,像代码中的consul标签处理部分也仅适用于我司,如果要想看源码.见本博客下载即可。
相关文章:
利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置
文章目录 前言一、prometheus发现方式二、监控指标注册架构图三、部分代码展示1.核心思想2.代码目录3、程序入口函数剖析4、settings配置文件5、初始化配置文件及consul6、全局变量7、配置config8、公共方法目录common9、工具目录tools10、service层展示11、命令行参数12、Make…...
Python爬虫介绍
Python 作为一种广泛应用的编程语言,在 Web 开发、大数据开发、人工智能开发和嵌入式开发等领域都有着重要的应用。 Python 的易学性、清晰性和可移植性等特点使它得到很多技术人士的喜爱。对于数据科学和机器学习领域的程序员来说,Python 提供了强大的…...
Linux 进程管理
一、查看进程 使用ps -aux进行查看,其中a表示列出所有进程信息,u以用户格式显示进程信息,x显示后台进程参数,也可以使用| grep 进行进程的筛选 以下是显示进程后的示意 USER为进程执行的用户 PID为进程号 %CPU为该进程的cpu占用…...
【车载测试】CAN协议、CAN- FD协议和FlexRay协议 区别
【上半场电动化,下半场智能化】 一、CAN协议 和 CAN- FD协议的区别 CAN(Controller Area Network)协议是一种广泛用于汽车和工业控制系统等领域的现场总线协议。CAN- FD(Flexible Data Rate)协议是对CAN协议的扩展&am…...
对日期的处理
对日期的处理 对编码进行统一,在脚本最开始: # -*- coding: utf-8 -*-这里涉及到两个操作,一个是将数据进行标准化,比如有些日期是2024/05/06这并不符合日期的标准格式,需要转换成这样的2024-05-06 def tran_std(st…...
赵丽颖纯白茉莉绽放温柔之美
赵丽颖纯白茉莉,绽放温柔之美在这个繁忙喧嚣的娱乐圈,赵丽颖以其独特的魅力,成为了无数人心中的白月光。近日,赵丽颖工作室发布了一组live图,她身着一袭温柔白裙,宛如一朵盛开的纯白茉莉花,美得…...
软考高级论文真题“论湖仓一体架构及其应用”
论文真题 随着5G、大数据、人工智能、物联网等技术的不断成熟,各行各业的业务场景日益复杂,企业数据呈现出大规模、多样性的特点,特别是非结构化数据呈现出爆发式增长趋势。在这一背景下,企业数据管理不再局限于传统的结构化OLTP…...
CentOS系统查看版本的各个命令
cat /etc/centos-release 查看CentOS版本 uname -a 命令的结果分别代表:当前系统的内核名称、主机名、内核发型版本、节点名、系统时间、硬件名称、硬件平台、处理器类型以及操作系统名称 cat /proc/version 命令用于查看Linux内核的版本信息。执行该命令后…...
[保姆级教程]uniapp实现底部导航栏
文章目录 前置准备工作安装HBuilder-X新建uniapp项目教程使用HBuilder-X启动uniapp项目教程 实现底部导航栏package.json中配置导航栏详细配置内容 前置准备工作 安装HBuilder-X 详细步骤可看上文》》 新建uniapp项目教程 详细步骤可看上文》》 使用HBuilder-X启动uniapp项…...
STM32多功能交通灯系统:从原理到实现
一、功能说明 本交通灯系统采用先进的stm32f103c8t6微处理器为核心控制单元。系统设置东南西北四个方向各配置两位数码管,用以精准展示5至99秒的时间范围,并且允许用户根据实际需求进行灵活调整。 在信号灯配置方面,每个方向均配备左转、直…...
Pip换源秘籍:让你的Python包飞行起来!
在Python的包管理中,Pip是最重要的工具之一。它允许开发者从Python Package Index (PyPI)安装包,但有时由于网络问题或服务器负载过高,直接从PyPI安装包可能会非常慢。这时,更换Pip源到一个更快的镜像站点是一个常见的解决方案。本…...
Flutter TIM 项目配置
目录 1. 设计说明 2. 参考资料索引 Flutter SDK 服务端 Rest API 腾讯后台 其他 3. TIM 整体架构 第一部分:APP 端 第二部分:腾讯服务器 第三部分:三方服务 第四部分:你自己的服务器 4. TIM SDK 集成 TUIK 含 UI 集成…...
【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(8)
Hi٩(๑o๑)۶, 各位深海王国的同志们,早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督继续为大家带来系列——小学生都能玩的单片机!带你一周内快速走进嵌入式的大门,let’s go! (8&#x…...
第5天:视图与模板进阶
第5天:视图与模板进阶 目标 掌握视图逻辑和模板渲染,包括不同类型的视图、自定义模板标签和过滤器,以及模板继承和包含的概念。 任务概览 学习函数视图和类视图的使用。编写自定义模板标签和过滤器。理解模板的继承和包含机制。 详细步骤…...
线程间通信方式(互斥(互斥锁)与同步(无名信号量、条件变量))
1通信机制:互斥与同步 线程的互斥通过线程的互斥锁完成; 线程的同步通过无名信号量或者条件变量完成。 2 互斥 2.1 何为互斥? 互斥是在多个线程在访问同一个全局变量的时候,先让这个线程争抢锁的资源,那个线程争抢…...
Android使用data uri启动activity或service
设定AndroidManifest.xml 在AndroidManifest.xml文件中,我们可以设定activity或service的data。 <!-- activity定义方式 --> <activityandroid:name".page.main.MainActivity"><intent-filter><action android:name"an…...
能理解你的意图的自动化采集工具——AI和爬虫相结合
⭐️我叫忆_恒心,一名喜欢书写博客的研究生👨🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支…...
基于SpringBoot+大数据城市景观画像可视化设计和实现
💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…...
Oracle表中的数据量达到30万条
当Oracle表中的数据量达到30万条,并且查询性能过慢时,增加索引是一个有效的优化方案。以下是一些建议来增加索引以提高查询性能: 分析查询需求: 首先,需要明确哪些查询是经常执行的,以及这些查询的WHERE子…...
【python】python学生成绩数据分析可视化(源码+数据+论文)【独一无二】
👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
