使用Go语言实现轻量级消息队列
文章目录
- 一、引言
- 1.1 消息队列的重要性
- 1.2 为什么选择Go语言
- 1.3 本文实现的轻量级消息队列特点
- 二、核心设计
- 2.1 消息队列的基本概念
- 2.1.1 消息类型定义
- 2.1.2 消息结构设计
- 2.2 架构设计
- 2.2.1 基于Go channel的实现方案
- 2.2.2 单例模式的应用
- 2.2.3 并发安全设计
- 2.3 消息发布与订阅
- 2.3.1 Publish方法实现
- 2.3.2 Consume方法实现
- 2.4 消费者管理
- 2.4.1 ConsumerManager设计
- 2.4.2 消费者注册机制
- 2.4.3 消费者生命周期管理
- 2.5 消息分发机制
- 2.5.1 多订阅者支持
- 2.5.2 消息广播实现
- 2.5.3 错误处理机制
- 2.6 并发控制
- 2.7 资源管理
- 三、使用示例
- 3.1 基本使用
- 四、性能优化
- 4.1 通道缓冲区设置
- 4.2 并发处理优化
- 4.3 内存管理建议
- 五、最佳实践
- 5.1 错误处理建议
- 5.2 日志记录策略
- 5.3 测试方法
- 5.4 部署注意事项
- 六、总结与展望
- 6.1 实现总结
- 6.2 可能的改进方向
- 6.3 与其他消息队列的对比
一、引言
在现代分布式系统中,消息队列扮演着至关重要的角色。它不仅能够解耦系统组件,还能提高系统的可扩展性和可靠性。Go语言以其高效的并发处理能力和简洁的语法,成为实现消息队列的理想选择。
1.1 消息队列的重要性
消息队列在系统中主要用于以下几个方面:
- 解耦:通过消息队列,系统的生产者和消费者可以独立演化。
- 削峰填谷:在高并发场景下,消息队列可以缓冲请求,平滑流量。
- 可靠性:通过持久化和重试机制,消息队列可以提高系统的可靠性。
1.2 为什么选择Go语言
Go语言的优势在于:
- 高效的并发处理:Go语言的goroutine和channel使得并发编程变得简单而高效。
- 简洁的语法:Go语言的语法简洁明了,易于维护。
- 强大的标准库:Go语言的标准库提供了丰富的功能,减少了对第三方库的依赖。
1.3 本文实现的轻量级消息队列特点
实现的消息队列具有以下特点:
- 基于Go channel:利用Go语言的channel实现消息的发布和订阅。
- 支持多订阅者:同一消息类型可以有多个订阅者。
- 并发安全:通过互斥锁保证并发安全。
二、核心设计
在设计消息队列时,遵循了简单而高效的原则。以下是设计的核心要点。
完整流程
2.1 消息队列的基本概念
2.1.1 消息类型定义
在消息队列中,消息类型用于标识不同的消息:
type MessageType stringconst (HealthRecordSaved MessageType = "health.record.saved"
)
2.1.2 消息结构设计
消息结构包含消息的ID、类型和内容:
type Message struct {ID stringType MessageTypeBody []byte
}
2.2 架构设计
2.2.1 基于Go channel的实现方案
Go channel是Go语言中用于通信的核心机制。利用channel实现了消息的发布和订阅:
type GoMQ struct {queues map[MessageType]chan *Messagesubscribers map[MessageType][]chan *Messagemu sync.RWMutexclosed bool
}
2.2.2 单例模式的应用
为了确保消息队列的唯一性,使用单例模式:
var (instance *GoMQonce sync.Once
)func NewGoMQ() *GoMQ {once.Do(func() {instance = &GoMQ{queues: make(map[MessageType]chan *Message),subscribers: make(map[MessageType][]chan *Message),}})return instance
}
2.2.3 并发安全设计
在并发环境中,数据的一致性和安全性至关重要。通过互斥锁(sync.RWMutex
)来保证并发安全。
2.3 消息发布与订阅
2.3.1 Publish方法实现
发布消息时,首先检查队列是否存在,然后将消息发送到队列:
func (q *GoMQ) Publish(ctx context.Context, message *Message) error {q.mu.RLock()queue, exists := q.queues[message.Type]q.mu.RUnlock()if !exists {return errors.New("no consumer for message type")}select {case queue <- message:return nilcase <-ctx.Done():return ctx.Err()default:return errors.New("queue is full")}
}
2.3.2 Consume方法实现
订阅者通过Consume
方法注册到特定的消息类型:
func (q *GoMQ) Consume(ctx context.Context, queueTypes []MessageType, handler func(message *Message) error) error {q.mu.Lock()defer q.mu.Unlock()subscriber := make(chan *Message, 1000)for _, queueType := range queueTypes {if _, exists := q.queues[queueType]; !exists {q.queues[queueType] = make(chan *Message, 1000)}q.subscribers[queueType] = append(q.subscribers[queueType], subscriber)}go func() {for {select {case <-ctx.Done():returncase msg := <-subscriber:if err := handler(msg); err != nil {continue}}}}()return nil
}
2.4 消费者管理
2.4.1 ConsumerManager设计
消费者管理器负责管理和启动所有消费者:
type ConsumerManager struct {consumers []Consumerqueue QueueManager
}
2.4.2 消费者注册机制
消费者通过Register
方法注册到管理器:
func (m *ConsumerManager) Register(consumer Consumer) {m.consumers = append(m.consumers, consumer)
}
2.4.3 消费者生命周期管理
通过StartAll
方法启动所有注册的消费者:
func (m *ConsumerManager) StartAll(ctx context.Context) error {var wg sync.WaitGrouperrChan := make(chan error, len(m.consumers))for _, consumer := range m.consumers {wg.Add(1)go func(c Consumer) {defer wg.Done()if err := c.Start(ctx); err != nil {errChan <- err}}(consumer)}wg.Wait()close(errChan)for err := range errChan {if err != nil {return err}}return nil
}
2.5 消息分发机制
2.5.1 多订阅者支持
GoMQ支持同一消息类型的多订阅者,通过subscribers
字段管理:
subscribers map[MessageType][]chan *Message
2.5.2 消息广播实现
消息从队列中取出后,广播给所有订阅者:
for _, sub := range subscribers {select {case sub <- msg:default:}
}
2.5.3 错误处理机制
在消息处理过程中,错误会被记录并继续处理下一个消息。
2.6 并发控制
互斥锁使用
通过sync.RWMutex
实现读写锁,保证并发安全。
通道通信
利用Go语言的channel实现消息的异步通信。
上下文控制
通过context.Context
控制goroutine的生命周期。
2.7 资源管理
队列初始化
在NewGoMQ
中初始化队列和订阅者。
资源清理
通过Close
方法关闭所有队列和订阅者通道。
优雅关闭
在Close
方法中,确保所有资源被正确释放。
三、使用示例
3.1 基本使用
初始化队列
package mainimport ("context""fmt""go-mq/infrastructure/queue"
)func main() {// 消息队列的具体实现驱动queueManager := queue.NewGoMQ()// 创建消费者管理器consumerManager := queue.NewConsumerManager(queueManager)// 创建健康记录消费者healthRecordConsumer := consumer.NewHealthConsumer(queueManager)// 注册健康记录消费者consumerManager.Register(healthRecordConsumer)// 还可以继续注册其他的消费者// ...// 启动消费者管理器manager.StartAll(context.Background())
}
发布消息
func publishHealthRecord(mq queue.QueueManager) {ctx := context.Background()message := &queue.Message{ID: "1",Type: queue.HealthRecordSaved,Body: []byte("健康记录数据"),}if err := mq.Publish(ctx, message); err != nil {fmt.Printf("发布消息失败: %v\n", err)} else {fmt.Println("消息发布成功")}
}
订阅消息
type HealthConsumer struct {queue queue.QueueManager // 队列管理器
}func NewHealthConsumer(queue queue.QueueManager, userFacade *facade.UserFacade) *HealthConsumer {return &HealthConsumer{queue: queue, userFacade: userFacade}
}func (c *HealthConsumer) Start(ctx context.Context) error {return c.queue.Consume(ctx, []queue.MessageType{queue.HealthRecordSaved}, c.handleMessage)
}func (c *HealthConsumer) handleMessage(message *queue.Message) error {// TODO: 处理消费逻辑
}
四、性能优化
4.1 通道缓冲区设置
缓冲区大小的选择
queue := make(chan *Message, 1000)
缓冲区大小的调整
根据实际的业务需求和系统负载,可以动态调整缓冲区大小。
4.2 并发处理优化
Goroutine的使用
- 合理使用goroutine:避免过多的goroutine,以免增加调度开销。
- 使用sync.WaitGroup:在需要等待多个goroutine完成时,使用
sync.WaitGroup
进行同步。
锁的优化
- 减少锁的粒度:尽量缩小锁的作用范围,以减少锁的竞争。
- 使用读写锁:在读多写少的场景下,使用
sync.RWMutex
提高并发性能。
4.3 内存管理建议
内存分配优化
- 预分配内存:在初始化时预分配足够的内存,以减少运行时的分配。
- 使用对象池:通过对象池复用对象,减少内存分配和垃圾回收的开销。
五、最佳实践
5.1 错误处理建议
统一错误处理
handler := func(message *queue.Message) error {if err := processMessage(message); err != nil {log.Printf("处理消息失败: %v", err)return err}return nil
}
自定义错误类型
type MessageError struct {Code intMessage string
}func (e *MessageError) Error() string {return fmt.Sprintf("错误代码: %d, 错误信息: %s", e.Code, e.Message)
}
5.2 日志记录策略
选择合适的日志级别
- Info:记录正常的操作信息。
- Warning:记录可能导致问题的操作。
- Error:记录导致操作失败的错误。
日志格式化
建议使用结构化日志记录工具,如logrus
或zerolog
。
5.3 测试方法
单元测试
func TestProcessMessage(t *testing.T) {message := &queue.Message{ID: "1", Type: queue.HealthRecordSaved, Body: []byte("测试数据")}err := processMessage(message)if err != nil {t.Errorf("处理消息失败: %v", err)}
}
集成测试
在测试环境中模拟真实的消息发布和消费场景。
5.4 部署注意事项
资源配置
根据系统的负载情况,调整CPU和内存的分配。
监控和报警
使用Prometheus等监控工具,实时监控系统的性能指标,并设置相应的报警策略。
六、总结与展望
6.1 实现总结
轻量级消息队列通过Go语言的channel机制实现了高效的消息发布和订阅。其主要特点包括简单易用、高效并发和灵活扩展。
6.2 可能的改进方向
持久化支持
引入持久化机制,如使用数据库或文件系统存储消息。
分布式支持
实现分布式消息队列,支持多节点的消息发布和消费。
更丰富的功能
引入更多的功能,如消息重试、消息优先级、延迟队列等。
6.3 与其他消息队列的对比
与其他成熟的消息队列(如RabbitMQ、Kafka)相比,更为轻量级,适合于对性能和资源要求较低的场景,如果要使用成熟的队列,只需定义对应的方法,并实现interfaces的接口,然后在最开始初始化队列驱动的时候,使用成熟的队列驱动,就可以使用成熟的队列了。
完整代码示例
go-mq
相关文章:
使用Go语言实现轻量级消息队列
文章目录 一、引言1.1 消息队列的重要性1.2 为什么选择Go语言1.3 本文实现的轻量级消息队列特点 二、核心设计2.1 消息队列的基本概念2.1.1 消息类型定义2.1.2 消息结构设计 2.2 架构设计2.2.1 基于Go channel的实现方案2.2.2 单例模式的应用2.2.3 并发安全设计 2.3 消息发布与…...
QT窗口相关控件及其属性
widget,PushButton,lineEdit等都是基于QWidget延展出来的 并不是完整的窗口,而是作为窗口的一部分 真正的窗口是QMainWindow 菜单栏 Qt中的菜单栏是通过QMenuBar这个类来实现的,一个主窗口最多只有一个菜单栏,位于主…...
OceanBase 复合索引指南
一、 什么是复合索引,与单列索引的区别是什么 1.1 什么是复合索引 复合索引是指在数据库表中由两个或更多列共同构成的索引,也称多列索引。其独特之处在于,它并非仅针对单一列建立索引,而是对多个列的组合进行索引,从…...
蛋白质大语言模型ESM介绍
ESM(Evolutionary Scale Modeling)是 Meta AI Research 团队开发的一系列用于蛋白质的预训练语言模型。这些模型在蛋白质结构预测、功能预测和蛋白质设计等领域展现出了强大的能力。以下是对 ESM 的详细介绍: 核心特点 大规模预训练:基于大规模蛋白质序列数据进行无监督学…...
回归测试:保障软件质量的重要防线
在软件开发的生命周期中,变更无处不在——新功能添加、缺陷修复、性能优化或代码重构。但每一次变更都可能像投入平静水面的石子,引起意想不到的涟漪效应。这就是回归测试(Regression Testing)存在的意义,它是软件质量保障体系中不可或缺的一…...
51单片机中断
80C51 单片机的中断源及其默认优先级(从高到低): 优先级中断源中断号1️⃣外部中断 0 (INT0)IE0,编号 02️⃣定时器 0 (T0)TF0,编号 13️⃣外部中断 1 (INT…...
Ollama 常见命令速览:本地大模型管理指南
Ollama 常见命令速览:本地大模型管理指南 一、什么是 Ollama? Ollama 是一个轻量级工具,允许用户在本地快速部署和运行大型语言模型(LLM),如 Llama、DeepSeek、CodeLlama 等。其命令行工具设计简洁&#…...
LSPatch官方版:无Root Xposed框架,自由定制手机体验
在Android设备的自定义和优化过程中,Xposed框架一直是一个强大的工具。然而,许多用户因为Root操作的复杂性和风险而望而却步。今天,我们要介绍的 LSPatch官方版,就是这样一款基于LSPosed核心的无Root Xposed框架解决方案。它不仅提…...
星火燎原:大数据时代的Spark技术革命在数字化浪潮席卷全球的今天,海量数据如同奔涌不息的洪流,传统的数据处理方式已难以满足实时、高效的需求。
星火燎原:大数据时代的Spark技术革命 在数字化浪潮席卷全球的今天,海量数据如同奔涌不息的洪流,传统的数据处理方式已难以满足实时、高效的需求。Apache Spark作为大数据领域的璀璨明星,凭借其卓越的性能和强大的功能,…...
Spark-Streaming(三)
一. kafka和flume的整合 任务需求一:利用flume监控某目录中新生成的文件,将监控到的变更数据发送给kafka,kafka将收到的数据打印到控制台 1. 在flume/conf/目录下添加flume-kafka.conf文件 配置文件如下 2. 启动flume和kafka消费者 3. 传入数据 查看fl…...
深入了解C# List集合及两种常见排序算法:插入排序与堆排序
在C#中,List<T> 是一种常用的集合类型,它提供了对动态数组的灵活操作,能够方便地添加、删除和访问元素。而排序算法是计算机科学中非常重要的部分,插入排序和堆排序是两种经典的排序方法。本文将详细讲解C#中 List<T>…...
【软件设计师】模拟题三
以下是另外10道不重复的软考-软件设计师模拟试题,答案及解析统一放在最后: 试题部分 在软件工程中,敏捷开发(Agile Development)的核心实践之一是? A. 严格的文档编写 B. 基于里程碑的计划…...
什么是CN2专线?全面解析中国电信的高性能网络服务
一、CN2专线的定义 CN2专线(China Telecom Next Carrier Network)是中国电信推出的新一代高性能网络专线服务,旨在满足企业对高速、稳定、安全网络连接的深度需求。它基于优化的网络架构设计,通过分布式路由、多路径传输等技术&a…...
5.4 AgentLite:轻量级库,便于构建任务导向的LLM Agent系统
AgentLite 是一个轻量级、模块化设计的开源框架,专注于构建任务导向的基于大语言模型(LLM)的智能代理(Agent)系统。与其他功能丰富但较为复杂的框架(如 LangChain 或 AutoGen)相比,A…...
shell脚本3
for语句(一种循环控制结构,用于遍历列表或者范围内的元素,并对每个元素执行一段代码语法格式 for 变量名 in 取值列表 do 命令序列 done 入门示例: for i in 1 2 3 4 5 6 # for i in {1..6} 或 for i in …...
Kafka Tool(Offset Explorer)国内下载: Kafka可视化连接工具
Kafka Tool(现称为 Offset Explorer)是一款专为 Apache Kafka 集群设计的可视化连接客户端工具,主要用于消息的可视化浏览、消费者偏移量的管理、主题的管理以及数据的实时监控。作为一款商用软件,它以其直观的用户界面和强大的功…...
【JAVA】高并发场景下,如何保证数据的一致性和系统的稳定性?
数据一致性 数据库事务:使用数据库的事务机制,确保一组数据的相关操作要么全部成功,要么全部失败,从而保证数据的一致性。例如,在转账操作中,涉及到转出账户扣款和转入账户加款两个操作,这两个…...
【Linux篇】理解信号:如何通过信号让程序听从操作系统的指令
信号的悄然到来:当操作系统发出‘警告’时 一.信号1.1 基本概念1.2 产生信号方式1.2.1 键盘产生信号1.2.2 系统调用产生信号1.2.2.1 kill1.2.2.2 raise1.2.2.3 abort 1.2.3 调用系统命令1.2.4 异常1.2.5 软件条件产生信号1.2.5.1 pause1.2.5.2 alarm 二. 最后 信号的…...
统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
文章目录 一、背景二、说明三、页面四、代码前端MonitorServiceProcessPage.vueMonitorServiceProcessTable.vueMonitorServiceProcessTableButton.vueaddMonitorTask.vueproductOperation.vueshowMonitorTask.vueMonitorSystemLog.vueMonitorTask.vueMonitorTaskLog.vueRealti…...
WSL 安装过程整理
WSL 安装过程整理 一、WSL 安装教程二、安装后小技巧1、安装位置2、常用命令 三、在 WSL2 中安装 perf: 一、WSL 安装教程 史上最全的WSL安装教程 WSL2 最新最全帮助小白一步步详细安装教程 在WSL2 root 和普通用户的切换 轻松搬迁!教你如何将WSL从C盘迁…...
纯CSS吃豆人(JS仅控制进度)
一、效果展示 二、源码 html <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Pac-Man SVG Demo…...
redis 数据类型新手练习系列——Hash类型
redis 数据类型 Redis 主要支持以下几种数据类型: (1)string(字符串): 基本的数据存储单元,可以存储字符串、整数或者浮点数。 (2)hash(哈希):一个键值对集…...
如何使用@KafkaListener实现从nacos中动态获取监听的topic
1、简介 对于经常需要变更kafka主题的场景,为了实现动态监听topic的功能,可以使用以下方式。 2、使用步骤 2.1、添加依赖 <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactI…...
区块链如何达成共识:PoW/PoS/DPoS的原理、争议与适用场景全解
引言 区块链技术的核心在于去中心化网络中的信任机制,而共识算法是实现这一目标的关键。不同的共识机制在效率、安全性、去中心化程度等方面各有取舍。本文将深入解析三种主流共识机制——工作量证明(PoW)、权益证明&am…...
Oracle for Linux安装和配置(11)——Oracle安装和配置
11.3. Oracle安装和配置 Linux上Oracle的安装及配置与Windows上差不多,只是安装软件的准备等有所不同,下面只对不同于Windows的部分进行较为详细的讲解,其他类似部分不再赘述。另外,无论选择使用虚机还是物理机,Oracle安装、配置和使用等方面几乎都是完全一样的。 11.3.…...
http协议详解附带c/c++服务器和客户端源码
http详解 代码部分HTTP请求结构示例HTTP客户端实现(使用Linux系统调用)简易HTTP服务器实现 深入解析HTTP协议:从基础到实践1. HTTP协议核心概念1.1 协议本质解读1.2 通信模型详解 2. 抓包分析实战2.1 Fiddler工具妙用2.2 报文结构拆解 3. 请求…...
JavaScript性能优化实战(5):数据结构与算法性能优化
JavaScript中常用数据结构性能对比 数据结构的选择对JavaScript应用的性能有着决定性的影响。不同的数据结构在不同操作上各有优劣,选择合适的数据结构能显著提升应用性能。本节将对JavaScript中常用的数据结构进行全面的性能对比分析。 基本数据结构时间复杂度概览 首先,…...
uniapp小程序开发入门01-快速搭建一个空白的项目并预览它
uniapp小程序开发入门01-快速搭建一个空白的项目并预览它!由于近期有市场需求和计划,构建一套自己的小程序,所以再次带领大家系统的过一遍,如何使用uniapp程序快速构建一套完整的项目。今天是第一小节,带领大家快速构建…...
UR5 UR5e机器人URDF文件
URDF全称为Unified Robot Description Format,中文可以翻译为“统一机器人描述格式”。与计算机文件中的.txt文本格式、.jpg图像格式等类似,URDF是一种基于XML规范、用于描述机器人结构的格式。根据该格式的设计者所言,设计这一格式的目的在于提供一种尽可能通用(as genera…...
ubuntu20.04安装x11vnc远程桌面
x11vnc是一个VNC服务器, 安装后我们可以不依赖外部的显示设备, 通过网络远程登录ubuntu桌面。 安装x11vnc sudo apt-get install x11vnc 设置VNC登录密码 sudo x11vnc -storepasswd /etc/x11vnc.pwd 设置x11vnc在开机时自动启动 新建如下文件: sudo vi /lib/systemd/sys…...
AKM旭化成微电子全新推出能量收集IC“AP4413系列”
旭化成微电子开始批量生产用于环保发电的电荷控制集成电路!优化充电电池的充放电,广泛应用于智能遥控器和蓝牙TMTag等设备。 01 概述 旭化成微电子株式会社(AKM)开发出面向小型二次电池(充电电池)的环境…...
机器人行业研究系列报告
新质生产力系列报告:2024年人形机器人核心场景发展洞察研究报告 具身机器人行业现状及未来趋势分析 2025 2025年人形机器人投资策略,量产元年,全球共振,百家争鸣 人形机器人行业深度报告(一):…...
利用JMeter代理服务器方式实现高效压测
前言 在当今快节奏的互联网时代,确保Web应用和服务能够在高负载下稳定运行变得至关重要。无论是电子商务平台、社交媒体网络还是在线教育服务,用户对网站响应速度和稳定性的期望从未如此之高。因此,性能测试不再是一个可选项,而是…...
NLP高频面试题(五十五)——DeepSeek系列概览与发展背景
大型模型浪潮背景 近年来,大型语言模型(Large Language Model, LLM)领域发展迅猛,从GPT-3等超大规模模型的崛起到ChatGPT的横空出世,再到GPT-4的问世,模型参数规模和训练数据量呈指数级增长。以GPT-3为例,参数高达1750亿,在570GB文本数据上训练,显示出模型规模、数据…...
2015-2023 各省 GDP 数据,用QuickBI 进行数据可视化——堆叠图!
嘿,数据爱好者们!今天咱要来一场刺激的数据冒险,深入剖析全国各省的 GDP 数据,而且会借助强大的 QuickBI 工具,用超酷炫的堆叠图让这些数据 “活” 起来,带你一眼看清经济格局! 地址࿱…...
MySQL优化(持续更新)笔记
一、insert优化 : 之前:项目通常是一条insert一条的执行,每一次都需要与MySQL进行建立连接进行网络传输,效率很低 现在: 1.- 批量插入(一条sql就行,一次500-1000) 可以与MyBatis…...
MySQL表的操作 -- 表的增删改查
目录 1. 表的创建2. 表的查看3. 表的修改4. 表的删除5. 总结 1. 表的创建 1.查看字符集及效验规则 2. 表的创建 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;创建用户表1 创建用…...
Java 数组:深度解析
前言 数组作为Java中最基础也是最强大的数据结构之一,其高效性和灵活性在性能关键型应用中无可替代。本文将从进阶使用开始,逐步深入探索Java数组的高级特性和大师级技巧,帮助开发者全面掌握数组技术的精髓。 一、数组基础回顾与性能特性 1.1 数组基本特性对比 特性Java数…...
【基于Qt的QQMusic项目演示第一章】从界面交互到核心功能实现
🌹 作者: 云小逸 🤟 个人主页: 云小逸的主页 🤟 motto: 要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在&…...
[Mybatis-plus]
简介 MyBatis-Plus (简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变。Mybatis-plus官网地址 注意,在引入了mybatis-plus之后,不要再额外引入mybatis和mybatis-spring,避免因为版本…...
【EDA】EDA中聚类(Clustering)和划分(Partitioning)的应用场景
在VLSI物理设计自动化中,聚类(Clustering)和划分(Partitioning)是两个互补但目标和应用场景截然不同的关键步骤,其核心区别如下: 一、应用阶段与核心目标 1. 聚类(Clustering&…...
PySide与PyQt对比:为何PySide是更优选择
PySide与PyQt对比:为何PySide是更优选择 引言 在Python桌面应用开发领域,Qt框架的绑定库一直是首选方案。两大主要选择—PySide和PyQt,虽然功能相似,但在许可证、性能和支持方面存在显著差异。本文将深入探讨为何PySide通常是更…...
LVGL移植高通矢量字库GT5SLAD3BFA
字库芯片: GT5SLAD3BFA MCU: STM32F429 LVGL版本:V8.4 一,实现gt_read_data() gt_read_data()函数的作用:与字库flash进行通信,函数的定义里调用spi发送数据和接收数据的接口。用户只需要实现该函数,就可以…...
7.0 sharpScada的sql数据的安装
本文介绍开源库SharpScada的配置过程。 1,还原数据库 2.打开SQL server2014配置启动器,并启用Named Pipes,以及TCP/IP 3.启动SQL Server服务中的SQL Server Browser 4.允许远程连接...
杂项知识点
杂项 1 激活函数1.1 sigmoid1.2 tanh1.3 Relu1.4 leakRelu 1 激活函数 常用的激活函数包括sigmoid tanh Relu leakRelu 1.1 sigmoid import torch import numpy as np import matplotlib.pyplot as plt # sigmoid tanh Relu leakRelu ## 1 sigmoid ### 1.1 代码复现sig…...
Android项目升级插件到kotlin 2.1.0后混淆网络请求异常
背景 项目kt插件1.9.24升级到2.1.0后打包编译release网络请求失败了。 retrofit版本2.9.0 错误详情 java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeat retrofit2.m.a(Unknown Source:2477)at retrofit2.K.invoke(U…...
uniapp 仿企微左边公司切换页
示例代码: <template><view class"container"><!-- 遮罩层 --><view class"mask" v-if"showSidebar" click"closeSidebar"></view><!-- 侧边栏 --><view class"sidebar"…...
Milvus(7):Schema、主字段和自动识别
1 Schema Schema 定义了 Collections 的数据结构。在创建一个 Collection 之前,你需要设计出它的 Schema。本页将帮助你理解 Collections 模式,并自行设计一个示例模式。 在 Zilliz Cloud 上,Collection Schema 是关系数据库中一个表的组合&a…...
Liunx服务上MySQL服务导致CPU炸了,使用kill -9 mysqld进程id后,无法启动MySQL
1.top命令后,可以看到mysqld沾满了cpu 2.然后我使用了kill -9 16594,杀死了mysqld进程 3.之后,查看mysql服务状态,发现对应的 www/serve/mysqld 目录不存在 sudo systemctl status mysqld4.使用命令查看操作 www/serve 目录的历…...
Java使用IText7动态生成带审批文本框的PDF文档
Java使用IText7动态生成带审批文本框的PDF文档 文章目录 Java使用IText7动态生成带审批文本框的PDF文档1.构建第一个框的起始坐标2.渲染第一个框3.渲染其他的审批框 测试结果示例 实现思路 使用Canvas进行相对定位和绝对定位来确定文本框内文字位置,用Rectangle通…...