这是我参与「第五届青训营」伴学笔记创作活动的第 3 天
编码规范&go
Go官方的Effective Go: go.dev/doc/effecti…
Introduction
Go is a new language. Although it borrows ideas from existing languages, it has unusual properties that make effective Go programs different in character from programs written in its relatives. A straightforward translation of a C++ or Java program into Go is unlikely to produce a satisfactory result—Java programs are written in Java, not Go. On the other hand, thinking about the problem from a Go perspective could produce a successful but quite different program. In other words, to write Go well, it's important to understand its properties and idioms. It's also important to know the established conventions for programming in Go, such as naming, formatting, program construction, and so on, so that programs you write will be easy for other Go programmers to understand.
This document gives tips for writing clear, idiomatic Go code. It augments the language specification, the Tour of Go, and How to Write Go Code, all of which you should read first.
Note added January, 2022: This document was written for Go's release in 2009, and has not been updated significantly since. Although it is a good guide to understand how to use the language itself, thanks to the stability of the language, it says little about the libraries and nothing about significant changes to the Go ecosystem since it was written, such as the build system, testing, modules, and polymorphism. There are no plans to update it, as so much has happened and a large and growing set of documents, blogs, and books do a fine job of describing modern Go usage. Effective Go continues to be useful, but the reader should understand it is far from a complete guide. See issue 28782 for context.
性能优化建议-Benchmark
什么是Benchmark???
benchmark是 go testing 库提供的,用来度量程序性能,算法优劣,指定一个时间(默认是1秒),看测试对象在达到时间上限时,最多能被执行多少次和在此期间测试对象内存分配情况。
它的特点
基准测试的代码文件必须以_test.go结尾 基准测试的函数必须以Benchmark开头 基准测试函数必须接受一个指向Benchmark类型的指针作为唯一参数 基准测试函数不能有返回值 b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰 最后的for循环很重要,被测试的代码要放到循环里 b.N是基准测试框架提供的,表示循环的次数
常用API
- b.StopTimer()
- b.StartTimer()
- b.ResetTimer()
- b.Run(name string, f func(b *B))
- b.RunParallel(body func(*PB))
- b.ReportAllocs()
- b.SetParallelism(p int)
- b.SetBytes(n int64)
- testing.Benchmark(f func(b *B)) BenchmarkResult
性能优化建议-Slice
slice预分配内存,使用make()初始化切片时提供容量信息
如果在后续使用过程中切片容量不够了,会重新用一个新的数组做底层数组,造成性能开销。
内存未释放问题 使用切片表达式,在已有切片基础上创建切片,不会创建新的底层数组而是会复用原来切片的底层数组,原切片较大,代码在原切片的基础上新建小切片。之后使用这个小切片实际上还是使用原先大切片底层数组,性能不高原底层数组在内存中有引用,得不到释放 解决方法就是可以使用copy函数 来代替使用切片表达式在已有切片基础上创建切片
性能优化建议-map
map 预分配内存
尽可能在使用make()初始化 map 时提供容量信息
空结构体
使用空结构体节省内存,空结构体struct{}实例不占用任何内存空间
m := make(map[int]struct{})
for i:=0;i<n;i++{
m[i] = struct{}{}
}
}
复制代码
使用string.Builder 对字符串进行拼接
func StrBuilder(n int,str string)string{
var builder strings Builder
for i:=0;i<n;i++{
builder.WriteString(str)
}
return builder.String()
}
复制代码
使用 atomic 包
go语言中锁的实现是通过操作系统来实现,属于系统调用
atomic 操作是通过硬件实现,效率比锁高
sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护一个变量
对于非数值操作,可以使用 atomic.Value ,能承载一个interface{}
引用
原文链接: blog.csdn.net/heshushun/a…