40分钟学 Go 语言高并发:sync包详解(下)
sync包详解(下)
学习目标
知识点 | 掌握程度 | 应用场景 |
---|---|---|
WaitGroup使用 | 熟练使用和理解原理 | 并发任务的同步等待 |
Once实现原理 | 理解底层实现和使用场景 | 单例模式、一次性初始化 |
Pool性能优化 | 掌握对象池的使用和调优 | 高并发下的内存优化 |
Cond应用场景 | 了解条件变量的使用方法 | 多线程协调和通信 |
1. WaitGroup的使用
1.1 WaitGroup基本原理
WaitGroup用于等待一组goroutine完成。它提供三个方法:
- Add(): 增加等待的goroutine数量
- Done(): 标记一个goroutine完成
- Wait(): 等待所有goroutine完成
让我们通过一个完整的例子来理解WaitGroup的使用:
package mainimport ("fmt""sync""time"
)// 任务执行器
type TaskExecutor struct {tasks []func() errorwg sync.WaitGrouperrChan chan errortimeout time.Duration
}func NewTaskExecutor(timeout time.Duration) *TaskExecutor {return &TaskExecutor{tasks: make([]func() error, 0),errChan: make(chan error, 100),timeout: timeout,}
}// 添加任务
func (te *TaskExecutor) AddTask(task func() error) {te.tasks = append(te.tasks, task)
}// 执行所有任务
func (te *TaskExecutor) Execute() []error {te.wg.Add(len(te.tasks))// 启动所有任务for i := range te.tasks {go func(taskID int, task func() error) {defer te.wg.Done()// 执行任务并捕获错误if err := task(); err != nil {select {case te.errChan <- fmt.Errorf("task %d failed: %w", taskID, err):default:// 错误channel满了就打印错误fmt.Printf("Error channel full, task %d error: %v\n", taskID, err)}}}(i, te.tasks[i])}// 等待任务完成或超时done := make(chan struct{})go func() {te.wg.Wait()close(done)}()// 等待完成或超时select {case <-done:// 所有任务完成case <-time.After(te.timeout):fmt.Println("Execution timed out")}// 收集所有错误close(te.errChan)var errors []errorfor err := range te.errChan {errors = append(errors, err)}return errors
}// 模拟任务
func createTask(id int, duration time.Duration, shouldFail bool) func() error {return func() error {fmt.Printf("Task %d started\n", id)time.Sleep(duration)if shouldFail {return fmt.Errorf("task %d failed", id)}fmt.Printf("Task %d completed\n", id)return nil}
}func main() {executor := NewTaskExecutor(5 * time.Second)// 添加一些测试任务executor.AddTask(createTask(1, 2*time.Second, false))executor.AddTask(createTask(2, 1*time.Second, true))executor.AddTask(createTask(3, 3*time.Second, false))executor.AddTask(createTask(4, 2*time.Second, true))executor.AddTask(createTask(5, 1*time.Second, false))// 执行任务并收集错误errors := executor.Execute()// 打印执行结果if len(errors) > 0 {fmt.Println("\nExecution completed with errors:")for _, err := range errors {fmt.Printf("- %v\n", err)}} else {fmt.Println("\nAll tasks completed successfully")}
}
1.2 WaitGroup执行流程
2. Once的实现原理
2.1 Once基本概念
sync.Once保证一个函数只执行一次,常用于单例模式或一次性初始化。
让我们实现一个使用Once的配置加载器:
package mainimport ("encoding/json""fmt""sync""time"
)// 配置结构
type Config struct {DatabaseURL string `json:"database_url"`RedisURL string `json:"redis_url"`APIKey string `json:"api_key"`MaxWorkers int `json:"max_workers"`
}// 配置管理器
type ConfigManager struct {config *Configonce sync.Once
}var (configManager *ConfigManagerinstanceOnce sync.Once
)// 获取ConfigManager单例
func GetConfigManager() *ConfigManager {instanceOnce.Do(func() {configManager = &ConfigManager{config: &Config{},}})return configManager
}// 加载配置
func (cm *ConfigManager) LoadConfig() (*Config, error) {var err errorcm.once.Do(func() {// 模拟从文件或远程加载配置time.Sleep(time.Second) // 模拟IO操作// 模拟JSON配置jsonConfig := `{"database_url": "postgres://user:pass@localhost:5432/db","redis_url": "redis://localhost:6379","api_key": "secret-key-123","max_workers": 10}`err = json.Unmarshal([]byte(jsonConfig), cm.config)if err == nil {fmt.Println("Configuration loaded successfully")}})if err != nil {return nil, fmt.Errorf("failed to load config: %w", err)}return cm.config, nil
}// 模拟配置使用
func useConfig(id int) {cm := GetConfigManager()config, err := cm.LoadConfig()if err != nil {fmt.Printf("Goroutine %d failed to get config: %v\n", id, err)return}fmt.Printf("Goroutine %d using config: DB=%s, Redis=%s, Workers=%d\n",id, config.DatabaseURL, config.RedisURL, config.MaxWorkers)
}func main() {// 模拟多个goroutine同时访问配置var wg sync.WaitGroupfor i := 0; i < 5; i++ {wg.Add(1)go func(id int) {defer wg.Done()time.Sleep(time.Duration(id*100) * time.Millisecond) // 错开启动时间useConfig(id)}(i)}wg.Wait()
}
2.2 Once实现流程图
3. Pool的性能优化
3.1 Pool的作用与原理
sync.Pool用于存储和复用临时对象,减少内存分配和GC压力。
让我们实现一个使用Pool优化的数据处理系统:
package mainimport ("bytes""encoding/json""fmt""sync""time"
)// 数据处理器
type DataProcessor struct {bufferPool *sync.PooljsonPool *sync.Pool
}// 示例数据结构
type DataItem struct {ID int `json:"id"`Name string `json:"name"`Value float64 `json:"value"`Timestamp time.Time `json:"timestamp"`
}// 创建新的数据处理器
func NewDataProcessor() *DataProcessor {return &DataProcessor{// 创建buffer对象池bufferPool: &sync.Pool{New: func() interface{} {return new(bytes.Buffer)},},// 创建数据对象池jsonPool: &sync.Pool{New: func() interface{} {return new(DataItem)},},}
}// 处理数据
func (dp *DataProcessor) ProcessData(data []byte) error {// 从对象池获取bufferbuf := dp.bufferPool.Get().(*bytes.Buffer)defer func() {buf.Reset()dp.bufferPool.Put(buf)}()// 从对象池获取数据对象item := dp.jsonPool.Get().(*DataItem)defer dp.jsonPool.Put(item)// 解析JSON数据if err := json.Unmarshal(data, item); err != nil {return fmt.Errorf("failed to unmarshal data: %w", err)}// 处理数据item.Value = item.Value * 1.1 // 示例处理:增加10%// 使用buffer进行JSON编码if err := json.NewEncoder(buf).Encode(item); err != nil {return fmt.Errorf("failed to encode result: %w", err)}// 在实际应用中,这里可能会将处理结果发送到某个目的地fmt.Printf("Processed: %s", buf.String())return nil
}func main() {processor := NewDataProcessor()var wg sync.WaitGroup// 模拟大量并发请求for i := 0; i < 100; i++ {wg.Add(1)go func(id int) {defer wg.Done()// 创建测试数据testData := DataItem{ID: id,Name: fmt.Sprintf("Item-%d", id),Value: float64(id * 100),Timestamp: time.Now(),}// 序列化测试数据data, err := json.Marshal(testData)if err != nil {fmt.Printf("Failed to marshal test data: %v\n", err)return}// 处理数据if err := processor.ProcessData(data); err != nil {fmt.Printf("Failed to process data: %v\n", err)}}(i)}wg.Wait()
}
3.2 Pool使用注意事项
- 对象的生命周期管理
- 内存泄漏风险
- 性能监控和调优
让我们继续完成Cond的应用场景部分。
4. Cond的应用场景
4.1 Cond基本概念
sync.Cond是一个条件变量,它在共享资源的状态变化时对多个goroutine进行协调。
让我们通过一个生产者-消费者模型来详细理解Cond的使用:
package mainimport ("fmt""sync""time"
)// 任务队列
type TaskQueue struct {mutex sync.Mutexcond *sync.Condtasks []stringmaxSize intclosed bool
}// 创建新的任务队列
func NewTaskQueue(size int) *TaskQueue {tq := &TaskQueue{tasks: make([]string, 0, size),maxSize: size,}tq.cond = sync.NewCond(&tq.mutex)return tq
}// 添加任务
func (tq *TaskQueue) Push(task string) error {tq.mutex.Lock()defer tq.mutex.Unlock()// 检查队列是否已关闭if tq.closed {return fmt.Errorf("task queue is closed")}// 等待队列有空余位置for len(tq.tasks) >= tq.maxSize {tq.cond.Wait()// 再次检查队列状态if tq.closed {return fmt.Errorf("task queue is closed")}}// 添加任务tq.tasks = append(tq.tasks, task)fmt.Printf("Task added: %s, queue size: %d\n", task, len(tq.tasks))// 通知等待的消费者tq.cond.Signal()return nil
}// 获取任务
func (tq *TaskQueue) Pop() (string, error) {tq.mutex.Lock()defer tq.mutex.Unlock()// 等待任务可用for len(tq.tasks) == 0 && !tq.closed {tq.cond.Wait()}// 检查队列是否已关闭且为空if len(tq.tasks) == 0 && tq.closed {return "", fmt.Errorf("task queue is closed and empty")}// 取出任务task := tq.tasks[0]tq.tasks = tq.tasks[1:]fmt.Printf("Task removed: %s, queue size: %d\n", task, len(tq.tasks))// 通知等待的生产者tq.cond.Signal()return task, nil
}// 关闭队列
func (tq *TaskQueue) Close() {tq.mutex.Lock()defer tq.mutex.Unlock()tq.closed = true// 通知所有等待的goroutinetq.cond.Broadcast()
}func main() {// 创建一个容量为3的任务队列queue := NewTaskQueue(3)var wg sync.WaitGroup// 启动3个生产者for i := 0; i < 3; i++ {wg.Add(1)go func(id int) {defer wg.Done()for j := 0; j < 5; j++ {task := fmt.Sprintf("Task-P%d-%d", id, j)err := queue.Push(task)if err != nil {fmt.Printf("Producer %d failed: %v\n", id, err)return}time.Sleep(time.Millisecond * 100) // 模拟生产耗时}}(i)}// 启动2个消费者for i := 0; i < 2; i++ {wg.Add(1)go func(id int) {defer wg.Done()for {task, err := queue.Pop()if err != nil {fmt.Printf("Consumer %d exit: %v\n", id, err)return}fmt.Printf("Consumer %d processed %s\n", id, task)time.Sleep(time.Millisecond * 200) // 模拟消费耗时}}(i)}// 等待生产者完成后关闭队列go func() {wg.Wait()fmt.Println("All producers finished, closing queue...")queue.Close()}()// 等待所有goroutine完成time.Sleep(time.Second * 5)fmt.Println("Main: exit")
}
4.2 Cond的工作流程
4.3 Cond的常见应用场景
-
生产者-消费者模式
- 队列满/空的等待条件
- 批量处理的条件同步
-
资源池管理
- 连接池的可用连接等待
- 工作池的任务分发
-
线程协调
- 启动信号的统一等待
- 任务完成的同步通知
-
状态变更通知
- 配置更新的广播
- 系统状态转换的通知
4.4 性能优化建议
- 条件检查
// 推荐做法
for !condition() {cond.Wait()
}// 不推荐做法
if !condition() {cond.Wait()
}
- 信号通知
// 单个等待者使用Signal
cond.Signal()// 多个等待者使用Broadcast
cond.Broadcast()
- 锁的范围
// 推荐做法
mu.Lock()
// 最小化临界区
mu.Unlock()// 不推荐做法
mu.Lock()
// 大量非临界区操作
mu.Unlock()
总结
知识要点回顾
- WaitGroup
- Add/Done/Wait的正确使用
- 并发任务的同步控制
- 错误处理和超时机制
- Once
- 单例模式实现
- 初始化控制
- 并发安全保证
- Pool
- 对象复用机制
- 内存优化策略
- 性能监控方法
- Cond
- 条件变量的使用
- 生产者-消费者模式
- 多goroutine协调
实践建议
- 代码质量
- 始终使用defer确保解锁
- 检查并处理所有错误情况
- 添加适当的超时机制
- 性能优化
- 最小化锁的范围
- 合理使用对象池
- 避免过度同步
- 调试技巧
- 使用race detector
- 添加详细的日志
- 监控关键指标
怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!
相关文章:
40分钟学 Go 语言高并发:sync包详解(下)
sync包详解(下) 学习目标 知识点掌握程度应用场景WaitGroup使用熟练使用和理解原理并发任务的同步等待Once实现原理理解底层实现和使用场景单例模式、一次性初始化Pool性能优化掌握对象池的使用和调优高并发下的内存优化Cond应用场景了解条件变量的使用…...
android 使用MediaPlayer实现音乐播放--权限请求
在Android应用中,获取本地音乐文件的权限是实现音乐扫描功能的关键步骤之一。随着Android版本的不断更新,从Android 6.0(API级别23)开始,应用需要动态请求权限,而到了android 13以上需要的权限又做了进一步…...
空间计算、物理计算、实时仿真与创造拥有「自主行为」的小狗 | 播客《编码人声》
「编码人声」是由「RTE开发者社区」策划的一档播客节目,关注行业发展变革、开发者职涯发展、技术突破以及创业创新,由开发者来分享开发者眼中的工作与生活。 虚拟世界与现实世界的界限逐渐模糊,已然成为不争的事实。但究竟哪些曾经的幻想已然…...
Day24 回溯算法part03
93.复原IP地址 本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了 题目链接/文章讲解:代码随想录 视频讲解:回溯算法如何分割字符串并判断是合法IP?| LeetCode:93.复原IP地址_哔哩哔哩_bilibili class Solution {private List<String> resul…...
PyTorch:如何使用TensorBoard优化和监控深度学习模型
如何使用TensorBoard优化和监控深度学习模型 为了提供一个更加详细和完整的指南关于如何使用 TensorBoard 进行深度学习模型的监控与优化,我们将从TensorBoard的基础知识开始,一步步探讨如何设置和利用其各项功能。 1. TensorBoard简介与基本架构 Ten…...
FastAPI重载不生效?解决PyCharm中Uvicorn无法重载/重载缓慢的终极方法!
文章目录 📖 介绍 📖🏡 演示环境 🏡📒 重载缓慢 📒📝 问题概述🚨 相关原因📝 解决方案一📝 解决方案二📝 解决方案三📝 解决方案四⚓️ 相关链接 ⚓️📖 介绍 📖 在使用FastAPI开发时,reload=True 本应让你在修改代码后自动重启服务,提升开发效率…...
利用 GitHub 和 Hexo 搭建个人博客【保姆教程】
利用 GitHub 和 Hexo 搭建个人博客 利用 GitHub 和 Hexo 搭建个人博客一、前言二、准备工作(一)安装 Node.js 和 Git(二)注册 GitHub 账号 三、安装 Hexo(一)创建博客目录(二)安装 H…...
【无标题】
通过shell脚本分析部署nginx网络服务 1.接收用户部署的服务名称 2.判断服务是否安装 已安装;自定义网站配置路径为/www;并创建共享目录和网页文件;重启服务 没有安装;安装对应的软件包 3.测试 判断服务是否成功运行&a…...
金融数据中心容灾“大咖说” | 美创科技赋能“灾备一体化”建设
中国人民银行发布的《金融数据中心容灾建设指引》(JR/T 0264—2024)已于2024年7月29日正式实施。这一金融行业标准对金融数据中心容灾建设中的“组织保障、需求分析、体系规划、建设要求、运维管理”进行了规范和指导。面对不断增加的各类网络、业务、应…...
数据集-目标检测系列- 荷花 莲花 检测数据集 lotus>> DataBall
数据集-目标检测系列- 荷花 莲花 检测数据集 lotus>> DataBall DataBall 助力快速掌握数据集的信息和使用方式,会员享有 百种数据集,持续增加中。 贵在坚持! 数据样例项目地址: * 相关项目 1)数据集可视化项…...
【SQL Server】华中农业大学空间数据库实验报告 实验六 视图
1.实验目的 通过课堂理论学习与实验课的实际操作,充分理解视图的相关概念,作用,以及特点,视图中定义的是对一个或多个基本表的查询语句,其本身并不保存数据,所有的数据都存储在数据库的表中,因…...
jetson orin系列开发版安装cuda的gpu版本的opencv
opencv安装包下载地址: https://github.com/opencv/opencv/扩展库下载地址: https://github.com/opencv/opencv_contrib1. 删除jetpack包中的opencv版本 原先的opencv库安装在目录/usr/lib/aarch64-linux-gnu/下(一般其他的第三方库也都安…...
android 使用SQLiteOpenHelper 如何优化数据库的性能
一、数据库设计优化 (Schema Design): 这是性能优化的基础。一个精心设计的数据库结构可以显著提高查询速度和减少存储空间。 范式化 (Normalization): 遵循数据库范式,特别是第一范式、第二范式和第三范式,可以消除数据冗余。冗余数据不仅浪费存储空间…...
海盗王集成网关和商城服务端功能golang版
之前用golang把海盗王的商城服务端和网关服务端都重写了一次。 后来在同时开启网关和商城服务时,发现窗口数量有点多,有时要找到商城窗口比较麻烦。 既然2个都是用golang govcl写的,是不是可以集成到一起,方便使用呢?…...
『大模型笔记』IBM技术团队:AI智能体与AI助手功能对比!
『大模型笔记』IBM技术团队:AI智能体与AI助手功能对比! 文章目录 一. 『大模型笔记』IBM技术团队:AI智能体与AI助手功能对比!AI 助手与 AI 智能体的角色类比AI 助手的特点与性能优化AI 智能体的自主性AI 助手与智能体的用例比较AI 技术的局限性与改进AI 未来发展趋势与协同…...
LeetCode 每日一题 2024/11/18-2024/11/24
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 11/18 661. 图片平滑器11/19 3243. 新增道路查询后的最短距离 I11/20 3244. 新增道路查询后的最短距离 II11/21 3248. 矩阵中的蛇11/22 3233. 统计不是特殊数字的数字数量1…...
n、nvm、nrm、pnpm、yarn各种指令大全
n mac的版本管理工具(可能与nvm冲突) 安装 # 使用 npm / yarn npm i -g n yarn global add n # 使用 brew brew install n环境变量 export PATH"/usr/local/n/versions/node:$PATH"命令详解 版本查看 # 查看 n 版本 n --version/-V # 查…...
详细描述一下Elasticsearch索引文档的过程?
大家好,我是锋哥。今天分享关于【详细描述一下Elasticsearch索引文档的过程?】面试题。希望对大家有帮助; 详细描述一下Elasticsearch索引文档的过程? Elasticsearch的索引文档过程是其核心功能之一,涉及将数据存储到…...
【shell编程】shell基础之for与while循环
shell基础(五) 声明:该笔记为up主 泷羽的课程笔记,本节链接指路。 警告:本教程仅作学习用途,若有用于非法行为的,概不负责。 for循环 for循环用于遍历一系列的值,通常为一个列表或…...
C++多线程编程入门教程(优质版)
一、引言 在当今的软件开发领域中,多线程编程的重要性日益凸显。它已然成为充分挖掘现代多核处理器性能、提升程序效率与响应速度的关键技术。C 作为一门强大的编程语言,其丰富的多线程编程工具和技术为开发者提供了广阔的施展空间。本文将引领读者踏入 …...
Spring监听的使用、原理、源码分析
一、原理分析 Spring监听的核心原理就是观察者模式。本文将对应观察者模式分析Spring监听的使用和原理。文章较长,跳转记得使用文章右边的目录。 1.1,观察者模式的组成 1,Subject:目标,即被观察者 维护了观察者列表&am…...
CSS布局学习2
flex布局中span会改变行为 在使用 Flex 布局时,盒子中的子元素(如 span)会自动成为 Flex 项目,并参与 Flex 布局的计算。具体原因如下: Flex 容器:当一个元素设置为 display: flex; 时,它会变…...
Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(三)
本篇紧跟第一篇, 和 第二篇无关 Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案 Oracle - 多区间按权重取值逻辑 ,分时区-多层级-取配置方案(二) 先说需求: 某业务配置表,按配置的时间区间及组织层级取方…...
Spring Cloud Netflix 系列:Eureka 经典实战案例和底层原理解析
文章目录 前言Eureka 简介架构设计工作流程 项目 demo 构建Eureka Server 的搭建Eureka Client 的配置补充说明 运行效果 深入使用Eureka 注册中心添加认证搭建 Eureka 集群实现高可用双节点集群搭建 运行效果补充说明为什么要配置 不同host 原理解析服务注册、心跳续期详细流程…...
ElasticSearch学习篇17_《检索技术核心20讲》最邻近检索-局部敏感哈希、乘积量化PQ思路
目录 场景在搜索引擎和推荐引擎中,对相似文章去重是一个非常重要的环节,另外是拍照识花、摇一摇搜歌等场景都可以使用它快速检索。 基于敏感性哈希的检索更擅长处理字面上的相似而不是语义上的相似。 向量空间模型ANN检索加速思路 局部敏感哈希编码 随…...
2024亚太杯国际赛C题参考文章50页+完整解题思路+数据处理+最终结果
中国宠物食品行业的发展趋势与汇率情景分析:基于多模型的量化预测与决策分析 一 、 摘要 本文针对宠物产业及相关产业的发展分析问题,采用多种数学建模方法和数据 分析技术,构建了一系列预测和评估模型。从宠物数量预测、全球市场分析、产业 …...
推荐几个 VSCode 流程图工具
Visual Studio Code(简称VSCode)是一个由微软开发的免费、开源的代码编辑器。 VSCode 发布于 2015 年,而且很快就成为开发者社区中广受欢迎的开发工具。 VSCode 可用于 Windows、macOS 和 Linux 等操作系统。 VSCode 拥有一个庞大的扩展市…...
渗透测试笔记——shodan(4)
声明: 学习视频来自B站up主 【泷羽sec】有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&am…...
一次封装,解放双手:Requests如何实现0入侵请求与响应的智能加解密
引言 之前写了 Requests 自动重试的文章,突然想到,之前还用到过 Requests 自动加解密请求的逻辑,分享一下。之前在做逆向的时候,发现一般医院的小程序请求会这么玩,请求数据可能加密也可能不加密,但是返回…...
c++中操作数据库的常用函数
在C中操作数据库,尤其是MySQL数据库,主要通过MySQL提供的C API或MySQL Connector/C库来实现。这些库提供了一系列的函数,使得开发者能够在C应用程序中执行数据库的连接、查询、更新、删除等操作。以下是C中操作MySQL数据库的一些常用函数&…...
CoAP 协议介绍:特性、应用与优劣势
CoAP 协议简介 CoAP 协议(Constrained Application Protocol)是一种专门为受限设备设计的互联网应用协议。它旨在让小型、低功耗的设备能够接入物联网(IoT)。该协议允许这些设备以最小的资源与更广泛的互联网进行通信。 CoAP 协…...
leetcode hot100【LeetCode 53.最大子数组和】java实现
LeetCode 53.最大子数组和 题目描述 给定一个整数数组 nums,找到一个具有最大和的连续子数组(至少一个元素),返回其最大和。 子数组是数组中的一个连续部分。 示例 1: 输入: nums [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续…...
MAC C语言 Helloword
在 macOS 系统上编写并运行一个简单的 “Hello, World!” 程序,你可以使用多种编程语言。下面我将以 C 语言为例,展示如何在 macOS 上编写、编译和运行这个经典的 “Hello, World!” 程序。 步骤 1: 安装 Xcode Command Line Tools macOS 系统上通常没…...
【过程控制系统】第6章 串级控制系统
目录 6. l 串级控制系统的概念 6.1.2 串级控制系统的组成 6.l.3 串级控制系统的工作过程 6.2 串级控制系统的分析 6.2.1 增强系统的抗干扰能力 6.2.2 改善对象的动态特性 6.2.3 对负荷变化有一定的自适应能力 6.3 串级控制系统的设计 6.3.1 副回路的选择 2.串级系…...
springboot:责任链模式实现多级校验
责任链模式是将链中的每一个节点看作是一个对象,每个节点处理的请求不同,且内部自动维护一个下一节点对象。 当一个请求从链式的首段发出时,会沿着链的路径依此传递给每一个节点对象,直至有对象处理这个请求为止。 属于行为型模式…...
如何构建高效的接口自动化测试框架?
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 在选择接口测试自动化框架时,需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说,使用Python相关的测试框架更为便捷。无论选…...
spring-logback引用外部文件
背景 在spring微服务开发和云部署中,都涉及到日志的收集,很多时候为例方便管理和开发,很多公司都会开发一些基础配置代码。其中日志就是很重要的部分, 为了方便部署、收集、查看,所以日志文件需要存储在同一个…...
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
文章目录 一、MyBatis-Plus简介二、快速入门1、环境准备2、将mybatis项目改造成mybatis-plus项目(1)引入MybatisPlus依赖,代替MyBatis依赖(2)配置Mapper包扫描路径(3)定义Mapper接口并继承BaseM…...
go项目中比较好的实践方案
工作两年来,我并未遇到太大的挑战,也没有特别值得夸耀的项目。尽管如此,在日常的杂项工作中,我积累了不少心得,许多实践方法也在思考中逐渐得到优化。因此,我在这里记录下这些心得。 转发与封装 这个需求…...
Windows之使用putty软件以ssh的方式连接Linux中文显示乱码
项目场景: 运行环境:Windows10 使用软件:putty 操作说明:以ssh的方式连接Linux 中文显示乱码 问题描述 Windows之使用putty软件以ssh的方式连接Linux中文显示乱码 原因分析: linux 机器的系统语言字符集与putty软件…...
springboot整合hive
springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…...
vxe-form table 修改表单数据校验的主题样式
在使用 vxe-form 表单校验时,数据校验可以支持2种主题样式 官网:https://vxeui.com 普通样式 通过设置 valid-config.theme‘normal’ 设置为普通样式 高亮样式 通过设置 valid-config.theme‘beautify’ 设置为高亮样式 <template><div&…...
【UE5】使用基元数据对材质传参,从而避免新建材质实例
在项目中,经常会遇到这样的需求:多个模型(例如 100 个)使用相同的材质,但每个模型需要不同的参数设置,比如不同的颜色或随机种子等。 在这种情况下,创建 100 个实例材质不是最佳选择。正确的做…...
一个计算频率的模块
先上代码 module _sync_reg #(parameter INIT 0,parameter ASYNC_RESET 0 ) (input clk,input rst,input in,output out );(* ASYNC_REG "TRUE" *) reg sync1; (* ASYNC_REG "TRUE" *) reg sync2;assign out sync2;generate if (ASYNC_RE…...
在SpringBoot项目中集成MongoDB
文章目录 1. 准备工作2. 在SpringBoot项目中集成MongoDB2.1 引入依赖2.2 编写配置文件2.3 实体类 3. 测试4. 文档操作4.1 插入操作4.1.1 单次插入4.1.2 批量插入 4.2 查询操作4.2.1 根据id查询4.2.2 根据特定条件查询4.2.3 正则查询4.2.4 查询所有文档4.2.5 排序后返回 4.3 删除…...
OpenJudge - 24:输出保留3位小数的浮点数
【题目来源】http://shnoip.openjudge.cn/level1/24/【题目描述】 读入一个单精度浮点数,保留3位小数输出这个浮点数。【输入格式】 只有一行,一个单精度浮点数。【输出格式】 也只有一行,读入的单精度浮点数。【输入样例】 12.34521【输出样…...
华为流程L1-L6业务流程深度细化到可执行
该文档主要介绍了华为业务流程的深度细化及相关内容,包括流程框架、建模方法、流程模块描述、流程图建模等,旨在帮助企业构建有效的流程体系,实现战略目标。具体内容如下: 华为业务流程的深度细化 流程层级:华为业务流程分为 L1 - L6 六个层级,L1 为流程大类,L2 为流程…...
Python中Tushare(金融数据库)入门详解
文章目录 Python中Tushare(金融数据库)入门详解一、引言二、安装与注册1、安装Tushare2、注册与获取Token 三、Tushare基本使用1、设置Token2、获取数据2.1、获取股票基础信息2.2、获取交易日历2.3、获取A股日线行情2.4、获取沪股通和深股通成份股2.5、获…...
Odoo中,要实现实时数据推送,SSE 与 WebSocket 该如何选择
目录 1. 技术特点对比 2. 使用场景 适合使用 SSE 的场景: 适合使用 WebSocket 的场景: 3. 优缺点总结 SSE 优点: SSE 缺点: WebSocket 优点: WebSocket 缺点: 4. 选择建议 选择 SSE 的条件&#x…...
02. Python基础知识
一、注释 在开发程序过程中,如果一段代码的逻辑比较复杂,不是特别容易理解,可以适当添加注释,以辅助自己或其他开发人员解读代码。注释是给程序员看的,为了让程序员方便阅读代码,解释器会忽略注释。在 Pyto…...