Golang性能优化的技巧分享

 更新时间:2023年07月31日 10:55:26   作者:燕过莲开  
性能优化的前提是满足正确可靠、简洁清晰等质量因素,针对 Go语言特性,本文为大家整理了一些Go语言相关的性能优化建议,感兴趣的可以了解一下

一.简介

​ 性能优化的前提是满足正确可靠、简洁清晰等质量因素。性能优化是综合评估,有时候时间效率和空间效率可能对立。针对 Go语言特性,下文介绍 Go 相关的性能优化建议。

二.性能优化建议

1.Benchmark

Benchmark能够为Go语言提供支持基准性能测试,能够提供实际的数据衡量。通过go test -bench=. -benchmen命令进行基准性能测试。

// from fib.go
func Fib(n int) int {
    if n <2{
        return n
    }
	return Fib(n-1) + Fib(n-2)
}
// from fib_test.go
func BenchmarkFib10(b *testing.B) {
    // run the Fib function b.N times
    for n := 0; n < b.N; n++{
        Fib(10)
    }
}

结果说明:

第四行第一个结果表示BenchmarkFib10是测试函数名8 表示GOMAXPROCS的值为8,第四行第二个结果表示一共执行1855870次即b.N的值,第四行第三个结果表示每次执行花费602.5ns,第四行第四个结果表示每次执行申请多大的内存,第四行第五个结果表示每次执行申请的几次内存。

2.slice

​ slice可以预分配内存,使用make() 初始化切片时提供容量信息。

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 )
    }
}

实验结果:

切片本质是一个数组片段的描述包括数组指针,片段的长度,片段的容量(不改变内存分配情况下的最大长度)。切片操作并不复制切片指向的元素,创建一个新的切片会复用原来切片的底层数组。

3.map

map预分配内存

func NoPreAlloc(size int) {
    data := make(map[int]int )
    for i := 0; i < size; i++ {
        data[i] = 1
    }
}
func PreAlloc(size int) {
    data := make(map[int]int, size)
    for i := 0; i < size; i++{
		data[i] = 1
    } 
}

实验结果:

不断向 map 中添加元素的操作会触发 map 的扩容,提前分配好空间可以减少内存拷贝和 Rehash 的消耗,根据实际需求提前预估好需要的空间。

4.字符串处理

使用strings.Builder

func ByteBuffer(n int, str string) string {
    buf := new( bytes .Buffer)
    for i := 0;i < n; i++ {
        buf.writeString(str)
    }
    return buf.String()
}

实验结果:

使用 +字符串拼接性能最差,strings.Builder,bytes.Buffer 相近,strings.Buffer 更快。字符串在 Go语言中是不可变类型,占用内存大小是固定的。使用 + 每次都会重新分配内存。strings.Builder,bytes.Buffer 底层都是 []byte 数组。内存扩容策略不需要每次拼接重新分配内存。

5.空结构体

空结构体 struct{}实例不占据任何的内存空间。可作为各种场景下的占位符使用,节省资源,空结构体本身具备很强的语义,即这里不需要任何值,仅作为占位符。

func EmptyStructMap(n int) {
    m := make(map[int]struct{})
    for i := 0;i < n; i++ {
        m[i] = struct{}{}
    }
}
func BoolMap(n int) {
    m := make(map[int]bool)
    for i := 0;i < n; i++ {
        m[i] = false
    }
}

实验结果:

实现 Set,可以考虑用 map 来代替。对于这个场景,只需要用到 map 的键,而不需要值。即使是将 map 的值设置为 bool 类型,也会多占据 1个字节空间。

6.atomic

使用atomic包

type atomicCounter struct {
    i int32
}
func AtomicAddOne( c
*atomicCounter) {
    atomic.AddInt32( &c.i, 1)
}
type mutexCounter struct {
    i int32
    m sync.Mutex
}
func MutexAddOne(c *mutexCounter) {
    c.m.Lock()
	c.i+
	c.m.Unlock()
}

实验结果:

锁的实现是通过操作系统来实现,属于系统调用。atomic 操作是通过硬件实现,效率比锁高。sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护一个变量。对于非数值操作,可以使用 atomic.Value,能承载一个interface。

三.小结

避免常见的性能陷阱可以保证大部分程序的性能。普通应用代码,不要一味地追求程序的性能。越高级的性能优化手段越容易出现问题。在满足正确可靠、简洁清晰的质量要求的前提下提高程序性能。

到此这篇关于Golang性能优化的技巧分享的文章就介绍到这了,更多相关Go性能优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析Go 字符串指纹

    浅析Go 字符串指纹

    这篇文章主要介绍了Go 字符串指纹的相关资料,帮助大家更好的理解和学习go语言,感兴趣的朋友可以了解下
    2020-09-09
  • Go-家庭收支记账软件项目实现

    Go-家庭收支记账软件项目实现

    这篇文章主要介绍了Go-家庭收支记账软件项目实现,本文章内容详细,具有很好的参考价值,希望对大家有所帮助,需要的朋友可以参考下
    2023-01-01
  • 以alpine作为基础镜像构建Golang可执行程序操作

    以alpine作为基础镜像构建Golang可执行程序操作

    这篇文章主要介绍了以alpine作为基础镜像构建Golang可执行程序操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • GoLang channel使用介绍

    GoLang channel使用介绍

    Channel 和 goroutine 的结合是 Go 并发编程的大杀器。而 Channel 的实际应用也经常让人眼前一亮,通过与 select,cancel,timer 等结合,它能实现各种各样的功能。接下来,我们就要梳理一下 channel 的应用
    2022-10-10
  • 浅析Go中原子操作的重要性与使用

    浅析Go中原子操作的重要性与使用

    这篇文章主要带大家一起探索 Go 中原子操作的概念,了解为什么它们是重要的,以及如何有效地使用它们,文中的示例代码讲解详细,需要的可以了解下
    2023-11-11
  • CSP communicating sequential processes并发模型

    CSP communicating sequential processes并发模型

    这篇文章主要为大家介绍了CSP communicating sequential processes并发模型,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Golang中大端序和小端序的处理

    Golang中大端序和小端序的处理

    大端序和小端序是描述多字节数据在内存中存储顺序的术语,本文主要介绍了Golang中大端序和小端序的处理,具有一定的参考价值,感兴趣的可以了解一下
    2025-02-02
  • Golang 空map和未初始化map的注意事项说明

    Golang 空map和未初始化map的注意事项说明

    这篇文章主要介绍了Golang 空map和未初始化map的注意事项说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言LeetCode500键盘行题解示例详解

    Go语言LeetCode500键盘行题解示例详解

    这篇文章主要为大家介绍了Go语言LeetCode500键盘行题解示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Golang Cron 定时任务的实现示例

    Golang Cron 定时任务的实现示例

    这篇文章主要介绍了Golang Cron 定时任务的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05

最新评论