高质量编程与性能调优实战

简介:

  • 性能优化的前提是满足正确可靠,简洁清晰等质量因素
  • 性能优化是综合评估,有时候时间效率和空间效率可能对立

性能优化建议–Benchmark

go语言提供了支持基准性能测试,如何使用得去查一查

slice

  • slice预分配内存,尽可能在使用make()初始化切片时提供容量信息

    data := make([]int,0)
    data := make([]int,0,10)
    
  • 切片的底层实现就是可扩容的链表

  • 陷阱:大内存未释放

    1. 在已有的切片上创建切片,不会创建新的底层数组
    2. 原切片较大,代码在原切片的基础上新建小切片
    3. 原底层数组在内存中引用,得不到释放
  • 可使用copy替代re-slice

    func GetLastBySlice(origin []int) []int{
    	return origin[len(origin) - 2:]
    }
    
    // 下面这个节省的空间更多
    fun getLastByCopy(origin []int) []int{
    	result := make([]int,2)
    	copy(result,origin[len(origin) - 2:])
    	return result
    }
    

map

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

strings.Buider进行字符串处理

  • 使用+拼接性能最差,strings.Buider,bytes.Buffer相近,strings。Buffer更快
  • 字符串在go里面时不可变类型,占用大小固定
  • 使用+每次都会重新分配内存
  • strings.Buider和bytes.Buffer底层都是使用[]byte数组

使用空结构体节省内存

使用atomic包

  • 锁的实现是通过操作系统来实现,属于系统调用, 调用成本很高

  • atomic操作是通过硬件实现,效率比锁高

  • sync.Mutex应该用来保护一段逻辑,。不仅仅用于保护一个变量

  • 对于非值操作,可以使用atomic.Value,能承载一个interface{}

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

小结:

  • 避免常见的性能陷阱可以保证大部分程序的功能
  • 普通应用代码,不要一味地追求程序的性能
  • 越高级的性能优化手段越容易出现问题
  • 在满足正确可靠,简洁清晰的质量要求的前提下提高程序性能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值