Go语言中提供了支持基准性能测试的benchmark工具。
go test -bench=. -benchmem
benchmark的测试代码如下:
func Fib(n int) int {
if n < 2 {
return n
}
return Fib(n-1) + Fib(n-2)
}
// BenchmarkFib10 run 'go test -bench=. -benchmem' to get the benchmark result
func BenchmarkFib10(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
Fib(10)
}
}
go test -bench=. -benchmem测试的结果如下:
测试的代码如下:NoPreAlloc函数和PreAlloc函数分别表示没有预分配内存和有预分配内存的情况。
func NoPreAlloc(size int) {
data := make([]int, 0)
for k := 0; k < size; k++ {
data = append(data, k)
}
}
func PreAlloc(size int) {
data := make([]int, 0, size)
for k := 0; k < size; k++ {
data = append(data, k)
}
}
进行性能测试后的结果如下图所示:
从上面的结果可以看出,slice在进行预分配容量比不进行预分配容量的性能提升了不少。
如下的代码展示了两种切片截取的方式:前者采用索引进行截取(共用底层数组),后者采用copy函数进行截取。提示:origin切片是一个很大的切片
func GetLastBySlice(origin []int) []int {
return origin[len(origin)-2:]
}
func GetLastByCopy(origin []int) []int {
result := make([]int, 2)
copy(result, origin[len(origin)-2:])
return result
}
采用如下的命令查看内存的占用情况:
go test -run=. -v
测试的结果如下图所示:
从上图可以看出,直接对大的切片进行截取小切片的内存开销远远大于采用copy函数
采用make()函数创建map的时候,应该尽可能的传入容量的参数,给map预分配一定大小的内存空间。提前分配好一定的内存空间可以减少内存拷贝和Rehash的开销。
测试的代码如下所示:第一个函数表示采用+的方式进行拼接字符串,第二种方式为采用strings.Bulider,第三种方式为采用bytes.Buffer。
func Plus(n int, str string) string {
s := ""
for i := 0; i < n; i++ {
s += str
}
return s
}
func StrBuilder(n int, str string) string {
var builder strings.Builder
for i := 0; i < n; i++ {
builder.WriteString(str)
}
return builder.String()
}
func ByteBuffer(n int, str string) string {
buf := new(bytes.Buffer)
for i := 0; i < n; i++ {
buf.WriteString(str)
}
return buf.String()
}
性能测试的结果:
如上图可知,在进行字符串的拼接的时候,strings.Bulider的性能最优,采用+号进行拼接的方法性能最差,bytes.Buffer性能次之。
空结构体不占用内存空间,可以在channel中用于传递信号,也可以用在map的value中,表示称hashset。空结构体可以节省系统的内存空间。