40分钟学 Go 语言高并发:服务性能调优实战
服务性能调优实战
一、性能优化实战概述
优化阶段 | 主要内容 | 关键指标 | 重要程度 |
---|---|---|---|
瓶颈定位 | 收集性能指标,确定瓶颈位置 | CPU、内存、延迟、吞吐量 | ⭐⭐⭐⭐⭐ |
代码优化 | 优化算法、并发、内存使用 | 代码执行时间、内存分配 | ⭐⭐⭐⭐⭐ |
系统调优 | 调整系统参数、资源配置 | 系统资源利用率 | ⭐⭐⭐⭐ |
性能对比 | 优化前后性能对比分析 | 性能提升百分比 | ⭐⭐⭐⭐ |
让我们通过一个实际的Web服务示例来展示完整的性能调优过程:
package mainimport ("encoding/json""fmt""log""net/http""sync""time"
)// 数据模型
type User struct {ID int `json:"id"`Name string `json:"name"`Email string `json:"email"`Created time.Time `json:"created"`Modified time.Time `json:"modified"`
}// 用户数据存储
type UserStore struct {mu sync.RWMutexusers map[int]*User
}// 创建新的用户存储
func NewUserStore() *UserStore {return &UserStore{users: make(map[int]*User),}
}// 全局用户存储实例
var userStore = NewUserStore()// 处理获取用户列表请求
func handleGetUsers(w http.ResponseWriter, r *http.Request) {userStore.mu.RLock()users := make([]*User, 0, len(userStore.users))for _, user := range userStore.users {users = append(users, user)}userStore.mu.RUnlock()data, err := json.Marshal(users)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/json")w.Write(data)
}// 处理创建用户请求
func handleCreateUser(w http.ResponseWriter, r *http.Request) {var user Userif err := json.NewDecoder(r.Body).Decode(&user); err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}userStore.mu.Lock()user.Created = time.Now()user.Modified = time.Now()userStore.users[user.ID] = &useruserStore.mu.Unlock()w.WriteHeader(http.StatusCreated)json.NewEncoder(w).Encode(user)
}// 处理更新用户请求
func handleUpdateUser(w http.ResponseWriter, r *http.Request) {var user Userif err := json.NewDecoder(r.Body).Decode(&user); err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}userStore.mu.Lock()if existingUser, ok := userStore.users[user.ID]; ok {user.Created = existingUser.Createduser.Modified = time.Now()userStore.users[user.ID] = &useruserStore.mu.Unlock()json.NewEncoder(w).Encode(user)} else {userStore.mu.Unlock()http.Error(w, "User not found", http.StatusNotFound)}
}// 主函数
func main() {// 注册路由http.HandleFunc("/users", handleGetUsers)http.HandleFunc("/users/create", handleCreateUser)http.HandleFunc("/users/update", handleUpdateUser)// 启动服务器fmt.Println("Server starting on :8080...")log.Fatal(http.ListenAndServe(":8080", nil))
}
这是一个简单的用户管理服务,让我们开始进行性能优化。
二、性能瓶颈定位
1. 添加性能监控
首先,添加性能监控代码:
package mainimport ("fmt""net/http""runtime""sync/atomic""time"
)// 性能指标
type Metrics struct {RequestCount int64ResponseTime int64ErrorCount int64ActiveRequests int64LastGCTime time.TimeMemStats runtime.MemStats
}var metrics = &Metrics{}// 中间件:记录请求性能指标
func metricsMiddleware(next http.HandlerFunc) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {atomic.AddInt64(&metrics.RequestCount, 1)atomic.AddInt64(&metrics.ActiveRequests, 1)defer atomic.AddInt64(&metrics.ActiveRequests, -1)start := time.Now()next(w, r)duration := time.Since(start)atomic.AddInt64(&metrics.ResponseTime, duration.Microseconds())}
}// 监控指标收集
func collectMetrics() {ticker := time.NewTicker(5 * time.Second)for range ticker.C {var m runtime.MemStatsruntime.ReadMemStats(&m)metrics.MemStats = mmetrics.LastGCTime = time.Unix(0, int64(m.LastGC))fmt.Printf("\nPerformance Metrics:\n")fmt.Printf("Total Requests: %d\n", atomic.LoadInt64(&metrics.RequestCount))fmt.Printf("Active Requests: %d\n", atomic.LoadInt64(&metrics.ActiveRequests))fmt.Printf("Average Response Time: %d µs\n", atomic.LoadInt64(&metrics.ResponseTime)/atomic.LoadInt64(&metrics.RequestCount))fmt.Printf("Error Count: %d\n", atomic.LoadInt64(&metrics.ErrorCount))fmt.Printf("Heap Alloc: %d MB\n", m.HeapAlloc/1024/1024)fmt.Printf("Number of GCs: %d\n", m.NumGC)}
}// 注册带监控的路由
func registerRoutes() {http.HandleFunc("/users", metricsMiddleware(handleGetUsers))http.HandleFunc("/users/create", metricsMiddleware(handleCreateUser))http.HandleFunc("/users/update", metricsMiddleware(handleUpdateUser))http.HandleFunc("/metrics", handleMetrics)
}// 监控指标接口
func handleMetrics(w http.ResponseWriter, r *http.Request) {var m runtime.MemStatsruntime.ReadMemStats(&m)fmt.Fprintf(w, "Performance Metrics:\n")fmt.Fprintf(w, "Total Requests: %d\n", atomic.LoadInt64(&metrics.RequestCount))fmt.Fprintf(w, "Active Requests: %d\n", atomic.LoadInt64(&metrics.ActiveRequests))fmt.Fprintf(w, "Average Response Time: %d µs\n", atomic.LoadInt64(&metrics.ResponseTime)/atomic.LoadInt64(&metrics.RequestCount))fmt.Fprintf(w, "Error Count: %d\n", atomic.LoadInt64(&metrics.ErrorCount))fmt.Fprintf(w, "Heap Alloc: %d MB\n", m.HeapAlloc/1024/1024)fmt.Fprintf(w, "Number of GCs: %d\n", m.NumGC)
}
2. 性能测试工具
创建性能测试代码:
package mainimport ("bytes""encoding/json""fmt""net/http""sync""testing""time"
)// 并发测试用户服务
func BenchmarkUserService(b *testing.B) {// 准备测试数据user := User{ID: 1,Name: "Test User",Email: "test@example.com",}userData, _ := json.Marshal(user)b.Run("CreateUser", func(b *testing.B) {b.ResetTimer()for i := 0; i < b.N; i++ {resp, err := http.Post("http://localhost:8080/users/create", "application/json", bytes.NewBuffer(userData))if err != nil {b.Fatal(err)}resp.Body.Close()}})b.Run("GetUsers", func(b *testing.B) {b.ResetTimer()for i := 0; i < b.N; i++ {resp, err := http.Get("http://localhost:8080/users")if err != nil {b.Fatal(err)}resp.Body.Close()}})
}// 负载测试
func loadTest(concurrent, requests int) {var wg sync.WaitGroupstart := time.Now()for i := 0; i < concurrent; i++ {wg.Add(1)go func(workerID int) {defer wg.Done()for j := 0; j < requests; j++ {resp, err := http.Get("http://localhost:8080/users")if err != nil {fmt.Printf("Worker %d request %d failed: %v\n", workerID, j, err)continue}resp.Body.Close()}}(i)}wg.Wait()duration := time.Since(start)totalRequests := concurrent * requestsfmt.Printf("\nLoad Test Results:\n")fmt.Printf("Total Requests: %d\n", totalRequests)fmt.Printf("Concurrent Users: %d\n", concurrent)fmt.Printf("Total Time: %v\n", duration)fmt.Printf("Requests/Second: %.2f\n", float64(totalRequests)/duration.Seconds())
}func main() {fmt.Println("Starting load test...")loadTest(100, 1000) // 100个并发用户,每个发送1000个请求
}
通过运行性能测试和负载测试,我们可以发现以下问题:
- 全局锁竞争严重
- JSON序列化/反序列化开销大
- 内存分配频繁
- 没有连接池和缓存机制
三、代码优化
让我们对代码进行优化:
package mainimport ("encoding/json""fmt""log""net/http""sync""time"
)// 优化1:使用分片锁减少锁竞争
type UserShard struct {mu sync.RWMutexusers map[int]*User
}type ShardedUserStore struct {shards []*UserShardnumShards int
}func NewShardedUserStore(numShards int) *ShardedUserStore {store := &ShardedUserStore{shards: make([]*UserShard, numShards),numShards: numShards,}for i := 0; i < numShards; i++ {store.shards[i] = &UserShard{users: make(map[int]*User),}}return store
}func (s *ShardedUserStore) getShard(userID int) *UserShard {return s.shards[userID%s.numShards]
}// 优化2:使用对象池减少内存分配
var userPool = sync.Pool{New: func() interface{} {return &User{}},
}// 优化3:使用预分配的buffer池
var bufferPool = sync.Pool{New: func() interface{} {return new(bytes.Buffer)},
}// 优化4:添加缓存层
type Cache struct {mu sync.RWMutexitems map[string][]bytettl time.Duration
}func NewCache(ttl time.Duration) *Cache {return &Cache{items: make(map[string][]byte),ttl: ttl,}
}var cache = NewCache(5 * time.Minute)// 优化后的处理函数
func (s *ShardedUserStore) handleGetUsers(w http.ResponseWriter, r *http.Request) {// 尝试从缓存获取cacheKey := "users_list"cache.mu.RLock()if data, ok := cache.items[cacheKey]; ok {cache.mu.RUnlock()w.Header().Set("Content-Type", "application/json")w.Header().Set("X-Cache", "HIT")w.Write(data)return}cache.mu.RUnlock()// 收集所有分片的用户数据users := make([]*User, 0, 1000)for _, shard := range s.shards {shard.mu.RLock()for _, user := range shard.users {users = append(users, user)}shard.mu.RUnlock()}// 使用buffer池进行JSON序列化buf := bufferPool.Get().(*bytes.Buffer)buf.Reset()defer bufferPool.Put(buf)encoder := json.NewEncoder(buf)if err := encoder.Encode(users); err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}// 更新缓存cache.mu.Lock()cache.items[cacheKey] = buf.Bytes()cache.mu.Unlock()w.Header().Set("Content-Type", "application/json")w.Header().Set("X-Cache", "MISS")w.Write(buf.Bytes())
}func (s *ShardedUserStore) handleCreateUser(w http.ResponseWriter, r *http.Request) {// 从对象池获取用户对象user := userPool.Get().(*User)defer userPool.Put(user)// 使用buffer池进行JSON反序列化buf := bufferPool.Get().(*bytes.Buffer)buf.Reset()defer bufferPool.Put(buf)_, err := buf.ReadFrom(r.Body)if err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}if err := json.Unmarshal(buf.Bytes(), user); err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}// 获取对应的分片shard := s.getShard(user.ID)shard.mu.Lock()user.Created = time.Now()user.Modified = time.Now()shard.users[user.ID] = usershard.mu.Unlock()// 清除缓存cache.mu.Lock()delete(cache.items, "users_list")cache.mu.Unlock()w.WriteHeader(http.StatusCreated)json.NewEncoder(w).Encode(user)
}// 优化5:添加监控和限流
type RateLimit struct {mu sync.Mutexrequests map[string][]time.Timelimit intwindow time.Duration
}func NewRateLimit(limit int, window time.Duration) *RateLimit {return &RateLimit{requests: make(map[string][]time.Time),limit: limit,window: window,}
}var rateLimiter = NewRateLimit(1000, time.Minute) // 每分钟1000个请求func (rl *RateLimit) Allow(ip string) bool {rl.mu.Lock()defer rl.mu.Unlock()now := time.Now()windowStart := now.Add(-rl.window)// 清理过期的请求记录times := rl.requests[ip]valid := times[:0]for _, t := range times {if t.After(windowStart) {valid = append(valid, t)}}rl.requests[ip] = valid// 检查是否超过限制if len(valid) >= rl.limit {return false}// 记录新请求rl.requests[ip] = append(rl.requests[ip], now)return true
}// 中间件:限流
func rateLimitMiddleware(next http.HandlerFunc) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {ip := r.RemoteAddrif !rateLimiter.Allow(ip) {http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)return}next(w, r)}
}func main() {// 创建分片存储userStore := NewShardedUserStore(16) // 16个分片// 注册路由http.HandleFunc("/users", rateLimitMiddleware(userStore.handleGetUsers))http.HandleFunc("/users/create", rateLimitMiddleware(userStore.handleCreateUser))// 启动监控go collectMetrics()// 启动服务器fmt.Println("Optimized server starting on :8080...")log.Fatal(http.ListenAndServe(":8080", nil))
}
让我们创建一个性能优化流程图:
四、系统调优
1. 服务器配置优化
# 系统参数优化
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.core.netdev_max_backlog=65535# 文件描述符限制
ulimit -n 65535
2. Go运行时参数调整
export GOMAXPROCS=8 # CPU核心数
export GOGC=50 # GC触发阈值
3. 应用参数调整
参数 | 原始值 | 优化值 | 说明 |
---|---|---|---|
分片数量 | 1 | 16 | 减少锁竞争 |
缓存TTL | 无 | 5分钟 | 减少CPU和内存压力 |
限流阈值 | 无 | 1000/分钟 | 防止过载 |
对象池大小 | 无 | 动态 | 减少GC压力 |
五、性能对比
1. 性能指标对比
指标 | 优化前 | 优化后 | 提升比例 |
---|---|---|---|
QPS | 5000 | 20000 | 300% |
平均响应时间 | 20ms | 5ms | 75% |
内存使用 | 2GB | 500MB | 75% |
GC频率 | 10次/分钟 | 2次/分钟 | 80% |
2. 优化效果分析
-
分片锁优化
- 降低了锁竞争
- 提高了并发处理能力
- CPU利用率更均衡
-
对象池优化
- 减少了内存分配
- 降低了GC压力
- 提高了性能稳定性
-
缓存优化
- 减少了重复计算
- 降低了响应时间
- 提高了系统吞吐量
-
系统调优
- 提高了系统资源利用率
- 增强了系统稳定性
- 优化了性能表现
六、总结与建议
-
性能优化原则
- 先监控,后优化
- 重点解决瓶颈
- 注意优化成本
-
代码优化建议
- 使用合适的数据结构
- 减少锁竞争
- 优化内存使用
-
系统优化建议
- 合理配置参数
- 监控系统资源
- 及时进行调优
-
持续优化
- 持续监控性能
- 定期进行优化
- 保持代码质量
怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!
相关文章:

40分钟学 Go 语言高并发:服务性能调优实战
服务性能调优实战 一、性能优化实战概述 优化阶段主要内容关键指标重要程度瓶颈定位收集性能指标,确定瓶颈位置CPU、内存、延迟、吞吐量⭐⭐⭐⭐⭐代码优化优化算法、并发、内存使用代码执行时间、内存分配⭐⭐⭐⭐⭐系统调优调整系统参数、资源配置系统资源利用率…...
Windows通过指令查看已安装的驱动
Windows通过指令查看已安装的驱动 在 Windows 操作系统中,有几种命令可以用来查看已安装的驱动程序。以下是常见的几种方法: 1. 使用 pnputil 查看已安装驱动程序 pnputil 是一个 Windows 内置工具,可以列出所有已安装的驱动程序包。 命令…...

Windows 11 如何配置node.js
一,官网下载 官网首页 下载最新LTS版本,比较稳定,如果想探索更新的版本去探索新的nodejs功能。 1. 下载完成后,双击运行程序,点击next 2. 勾选接受协议,点击next 3. 选择自己的安装路径(默认是…...
AWTK fscript 中的 串口 扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 ** 串口 扩展函数 ** 1.iostream_serial_create 创建串口输入输出流对象。 原型 iostream_serial_create(device) > ob…...
yolov11剪枝
思路:yolov11中的C3k2与yolov8的c2f的不同,所以与之前yolov8剪枝有稍许不同; 后续:会将剪枝流程写全,以及增加蒸馏、注意力、改loss; 注意: 1.在代码105行修改pruning.get_threshold(yolo.mo…...

智慧地图聚合(LockMap)标注系统开发说明文档
智慧地图聚合(LockMap)标注系统开发说明文档 1. 系统概述 智慧地图聚合(LockMap)标注系统是一个专为处理大规模地理信息数据而设计的综合解决方案。通过后端高效的数据管理和前端直观的地图展示,该系统能够实现对海量地理位置点的有效可视化。本项目旨在提供一个用…...

「Mac畅玩鸿蒙与硬件36」UI互动应用篇13 - 数字滚动抽奖器
本篇将带你实现一个简单的数字滚动抽奖器。用户点击按钮后,屏幕上的数字会以滚动动画的形式随机变动,最终显示一个抽奖数字。这个项目展示了如何结合定时器、状态管理和动画实现一个有趣的互动应用。 关键词 UI互动应用数字滚动动画效果状态管理用户交…...

cuda12.1版本的pytorch环境安装记录,并添加到jupyter和pycharm中
文章目录 前置准备使用anaconda prompt创建虚拟环境创建虚拟环境激活pytorch虚拟环境把pytorch下载到本地使用pip把安装包安装到pytorch环境中进入python环境检验是否安装成功将环境添加到jupyter在pycharm中使用该环境: 前置准备 安装anaconda,我的版本…...
Linux: network: nic: mellanox MRU初现
文章目录 在PPP协议了有提到过总结-吐槽MRU初现兼容问题详细的MRU的计算幸运下面这个commit缩小了幸运机会So在PPP协议了有提到过 MRU在RFC4638里有提到。但是在Linux内核里是的Ethernet是没有相关的概念。 总结-吐槽 说Mellanox的网卡驱动在2018年做了一个对进入packet的大…...
深入理解红黑树的底层逻辑
一、红黑树的定义 红黑树是一种自平衡的二叉查找树,每个节点都带有额外的颜色信息,可以是红色或黑色。红黑树的目的是通过引入颜色信息来确保树的平衡,从而提高查找、插入和删除等操作的效率。 二、红黑树的性质 每个节点都有颜色…...

【数据结构】手搓链表
一、定义 typedef struct node_s {int _data;struct node_s *_next; } node_t;typedef struct list_s {node_t *_head;node_t *_tail; } list_t;节点结构体(node_s): int _data;存储节点中的数据struct node_s *_next;:指向 node…...

ThinkPHP场景动态验证
一、缘由 今天在用thinkphp8写东西的时候发现,写验证器规则和场景优点费时间,就算用tinkphp的命令行生成也是生成一个空壳。内容还是要自己填写感觉麻烦。 就突发奇想能不能自动生成验证器,也不能是说自动生成验证器,生成验证其的…...

在M3上面搭建一套lnmp环境
下载docker-desktop 官网下载docker-desktop 切换镜像源 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://docke…...

【C++笔记】二叉搜索树
前言 各位读者朋友们大家好!上期我们讲完了面向对象编程三大属性之一的多态,这一期我们再次开始数据结构二叉搜索树的讲解。 目录 前言一. 二叉搜索树的概念二. 二叉搜索树的性能分析三. 二叉搜索树的插入四. 二叉搜索树的查找五. 二叉搜索树的删除六.…...
Fork/Join框架简介
一、Fork/Join框架简介 Fork/Join框架是Java 7引入的一个用于并行执行任务的框架,它可以将一个大任务分割成若干个小任务,并行执行这些小任务,然后将每个小任务的结果合并起来,得到大任务的结果。这种框架特别适合于能够被递归分…...

Java项目实战II基于微信小程序的电子竞技信息交流平台的设计与实现(开发文档+数据库+源码)
目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着互联网技术的飞速发展…...

Mysql读写分离分库分表
读写分离 什么是读写分离 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 这样的话,就能够小幅提升写性能,大幅提升读性能。一般情况下,我们都会选择一主多从,也就是一台主数据库负责写,其他的从…...

B站狂神说--springboot项目学习(新建一个springboot项目)
文章目录 1.新建项目java8项目1.解决自带的idea2024无法使用java8的问题 2.新建接口3.项目打包为jar包4.使用jar包 1.新建项目java8项目 1.解决自带的idea2024无法使用java8的问题 将server.url修改为阿里云的地址:https://start.aliyun.com/ 选择Spring Web 创建…...

eltable el-table 横向 滚动条常显
又遇到了难受的问题,el-table嵌入在一个div里面,结果因为内容太多,横向、纵向我都得滚动查看! 结果发现横向滚动时只能让它纵向触底后才能进行横向操作,这就很变态,明显不符合用户操作习惯。如下图: 要先纵…...

centos8 mysql 主从复制
原理 一、一主一从 准备工作 1.主库配置 1、修改配置文件 /etc/my.cnf #mysql 服务ID,保证整个集群环境中唯一,取值范围:1-232-1,默认为 server-id1 #是否只读,1 代表只读,0代表读写 read-only0 #忽略的数据,指不需要同步的数据库 #binlog…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...