go| go 性能优化入门之「Go代码重构:23倍的性能爆增」实践

简介: 最近在整理以前攒的 go 语言学习资料 -- 可能很多人都和我一样, 随手一个收藏, 不动手也不深入, 然后就过去了. 这次从故纸堆里扫出来, 当然不能错过

最近在整理以前攒的 go 语言学习资料 -- 可能很多人都和我一样, 随手一个收藏, 不动手也不深入, 然后就过去了. 这次从故纸堆里扫出来, 当然不能错过


资料:

- blog 地址: https://www.cnblogs.com/sunsky303/p/9296188.html

- 原作者已经提供好了代码: https://github.com/Deleplace/forks-golang-good-code-bad-code


学习到的知识:

- 使用 `go test` 进行 单测/压测

- 使用 `go tool` 进行 prof/trace

- 性能问题 debug 与优化思路


## let's party


- 作者准备好了代码 https://github.com/Deleplace/forks-golang-good-code-bad-code


- 确定基准, 使用 cpuprof 中的 `ns/op` 作为比较基准


```sh

cd bad

➜  bad git:(master) ✗ go test -bench=. -cpuprofile cpu.prof

goos: darwin

goarch: amd64

pkg: test/bad

BenchmarkParseAdexpMessage-8       18999      63848 ns/op

PASS

ok   test/bad 2.007s

```


- bad & good 代码对比: good 更惯用,更易读,利用go语言的细节, 后续的修改都基于 good 代码进行


- 查看 trace, 查看 CPU 使用情况


```sh

# 使用 trace 工具

go test -bench=. -trace trace.out

go tool trace trace.out # 会在默认浏览器中打开 trace

```


![image](https://upload-images.jianshu.io/upload_images/567399-82aaccf554e74881.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


- trace 分析: 放大 CPU 部分 -> 数千个小的彩色计算切片 + 空闲插槽 -> 一些核心处于空闲状态


- 首先进行竞争检测, **如果发生竞争, 比性能问题更严重**


```sh

# 竞争检测

go test -race

```


- 尝试 **不开协程**, 对应代码: https://github.com/Deleplace/forks-golang-good-code-bad-code/tree/nogo

```go

// 改动就一行

for _, line := range in {

// go mapLine(line, ch)

mapLine(line, ch)

}

```


- 使用 cpuprof, 查看热函数调用, 定位到瓶颈


```sh

# 1. 生成 cpuprof

go test -bench=. -cpuprofile cpu.prof

# 2. 生成 svg

go tool pprof -svg cpu.prof > cpu.svg

# 3. 使用 chrome 打开 svg 文件即可

```


- 根据瓶颈进行性能优化: https://github.com/Deleplace/forks-golang-good-code-bad-code/tree/performance

   - Fast custom trim func, to remove the space character only.

   - Use bytes.HasPrefix.

   - regexp.MustCompile is exactly what we need here.

   - Instead of regexp, use a loop: 10x speedupgap .

   - bytes.IndexByte is more appropriate here.

   - Small parseLine and findSubfields refactoring, same perf.

   - Remove startWith, call directly bytes.HasPrefix: slightly faster.


- 协程使用(调度)优化: 5k message + 20/100 协程

   - 20 协程: https://github.com/Deleplace/forks-golang-good-code-bad-code/commit/a2dfc2a6e8397ae1a3dd6f4be19786ebb45008be

   - 100 协程: https://github.com/Deleplace/forks-golang-good-code-bad-code/commit/26dbf25f2d01c96002a0e9ba66210a9e58ebbbbe


- 到此, 已经优化达到的效果


![image](https://upload-images.jianshu.io/upload_images/567399-0aa19ea22bfc478f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


- 还能不能再过分一点: 能, 用 `Lexer + Parser` https://github.com/Deleplace/forks-golang-good-code-bad-code/tree/lexerparser


## 写在最后

> 总算把一个很久很久之前的坑给填上了, 开心😺


- prof 相关: 可以定位热点函数, 方便定位瓶颈


```sh

go test -bench=. -cpuprofile cpu.prof # 压测, 生成 prof 文件

go tool pprof -svg cpu.prof > cpu.svg # 使用 prof 工具, prof 转为 svg, svg 可以使用 chrome 打开

```


- trace 相关: 可以查看 cpu 使用状态


```sh

go test -bench=. -trace trace.out

go tool trace trace.out

```


- goroutine 相关


首先要区分 CPU密集型任务/IO密集型任务, 协程更适合处理 **IO密集型任务**, 减少 IO wait 导致的 CPU 空转, 其次协程过多会导致协程调度的开销, 同样会造成性能损失


- 推荐使用 github desktop


切换分支, 查看 commit, so easy ~

目录
相关文章
|
6月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
406 86
|
5月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟蒋星熠Jaxonic,Go语言探索者。深耕云计算、微服务与并发编程,以代码为笔,在二进制星河中书写极客诗篇。分享Go核心原理、性能优化与实战架构,助力开发者掌握云原生时代利器。#Go语言 #并发编程 #性能优化
545 43
Go语言深度解析:从入门到精通的完整指南
|
6月前
|
Cloud Native 安全 Java
Go语言深度解析:从入门到精通的完整指南
🌟 蒋星熠Jaxonic,执着的星际旅人,用Go语言编写代码诗篇。🚀 Go语言以简洁、高效、并发为核心,助力云计算与微服务革新。📚 本文详解Go语法、并发模型、性能优化与实战案例,助你掌握现代编程精髓。🌌 从goroutine到channel,从内存优化到高并发架构,全面解析Go的强大力量。🔧 实战构建高性能Web服务,展现Go在云原生时代的无限可能。✨ 附技术对比、最佳实践与生态全景,带你踏上Go语言的星辰征途。#Go语言 #并发编程 #云原生 #性能优化
|
8月前
|
分布式计算 算法 安全
Go语言泛型-泛型约束与实践
Go语言中的泛型约束用于限制类型参数的范围,提升类型安全性。通过接口定义约束,可实现对数值类型、排序与比较等操作的支持。开发者既可使用标准库提供的预定义约束,如constraints.Ordered和constraints.Comparable,也可自定义约束以满足特定需求。泛型广泛应用于通用数据结构(如栈、队列)、算法实现(如排序、查找)及构建高效可复用的工具库,使代码更简洁灵活。
|
9月前
|
设计模式 人工智能 Go
go 依赖注入实践
依赖注入(DI)是一种软件设计模式,旨在降低代码耦合度,提高代码可测试性和可复用性。其核心思想是将依赖项从外部传入使用对象,而非由其内部创建。通过 DI,模块间关系更清晰,便于维护和扩展。常见实现包括方法注入和接口注入,适用于如 Go 等支持函数式编程和接口抽象的语言。
216 8
|
9月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
9月前
|
开发框架 安全 前端开发
Go Web开发框架实践:模板渲染与静态资源服务
Gin 是一个功能强大的 Go Web 框架,不仅适用于构建 API 服务,还支持 HTML 模板渲染和静态资源托管。它可以帮助开发者快速搭建中小型网站,并提供灵活的模板语法、自定义函数、静态文件映射等功能,同时兼容 Go 的 html/template 引擎,具备高效且安全的页面渲染能力。
|
8月前
|
Linux Go 开发者
Go语言泛型-泛型约束与实践
《Go语言实战指南》介绍了如何使用Go进行交叉编译,即在一个操作系统上编译出适用于不同系统和架构的二进制文件。通过设置GOOS和GOARCH环境变量,开发者可轻松构建跨平台程序,无需在每个平台上单独编译。Go从1.5版本起原生支持此功能,极大提升了多平台部署效率。
|
5月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
321 2
|
7月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
472 1