写点什么

技术优化:降本增效的常规实践

  • 2023-07-28
    日本
  • 本文字数:1847 字

    阅读完需:约 6 分钟

最近一年各大中小厂都在搞"优化",说到优化,目的还是"降本增效",降低成本,增加效益(效率)。


技术层面,也有一些降本增效的常规操作。


比如池化、io 缓冲区技术


池化技术 sync.Pool

sync.Pool 位于标准库,该文件提供了对临时对象的重复使用能力, 避免了频繁的 gc, 对并发协程是安全的。


该文件只有三个控制点:


  • New: 默认的临时对象

  • Get: 从池中哪一个临时对象

  • Put: 放回池中,以重用


下面使用基准测试进行 b.N*1000 次运算时的内存消耗。


package main
import ( "sync" "testing")
type Person struct { Age int}
var ( personPool = sync.Pool{ New: func() interface{} { // 设置默认值 return &Person{} }, })
func ExampleObjPool() { var p *Person for i := 0; i < 1000; i++ { for j := 0; j < 1000; j++ { p = personPool.Get().(*Person) p.Age = i + 1 personPool.Put(p) } } p = personPool.Get().(*Person) fmt.Println(p.Age) // output:1000}
func BenchmarkWithoutPool(b *testing.B) { var p *Person b.ReportAllocs() b.ResetTimer()
for i := 0; i < b.N; i++ { for j := 0; j < 1000; j++ { p = new(Person) // 每次均产生临时对象 p.Age = 23 } }}
func BenchmarkWithPool(b *testing.B) { var p *Person b.ReportAllocs() b.ResetTimer()
for i := 0; i < b.N; i++ { for j := 0; j < 1000; j++ { p = personPool.Get().(*Person) // 从池中复用对象 p.Age = 23 personPool.Put(p) // 放回以重用 } }}
复制代码


测试结果如下,sync.Pool[重用临时对象]的性能可见一斑。


bytes.Buffer

golang 很多方法内充斥了[]byte, 就连最常规的序列化/反序列化,返回值/参数都是[]byte, 但是 slice 是一个冷冰冰的数据结构,没有得心趁手的操作行为,还有很多陷阱。


  func Marshal(v any) ([]byte, error)  func Unmarshal(data []byte, v any) 
复制代码


A bytes.Buffer is a variable-sized buffer of bytes with Read and Write methods.


坦白讲 bytes.Buffer 并非底层优化机制, 实际提供了一个友好操作 slice 的方式。


下面的"abcd"字符串,先读取首字符、后面追加字符"e":


  var b bytes.Buffer  b.Write([]byte("abcd")) // 写入之后,自动扩容  rdbuf := make([]byte, 1)  _, err := b.Read(rdbuf) // 读取一个字节的数据,移动读off指针  if err != nil {    panic(err)  }  fmt.Println(b.String()) // 上面读取了一个字符,读off已经移动,现从读off位置转换为string  b.WriteByte('e')        // 在尾部写字符  fmt.Println(b.String())  fmt.Printf("%d, %d \n", b.Len(), b.Cap()) // Len方法返回还能读取的字符数量,Cap返回底层buf的容量  //output:bcd bcde4, 64
复制代码


bufio

Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.



首先我们需要知道当应用程序执行 IO 操作(从文件、网络和数据库读取或写入数据),它将触发底层的系统调用,从性能角度来看,这很繁重。


缓冲 IO 是一种技术,用于在传递之前暂时积累 IO 操作的结果。这种技术可以通过减少系统调用的数量来提高程序的速度。例如,如果您想要逐字节地从磁盘读取数据,与每次直接从磁盘读取每个字节不同,使用缓冲区 IO 技术,我们可以一次将一个数据块读入缓冲区,然后消费者可以以任何您想要的方式从缓冲区读取数据。通过减少繁重的系统调用,性能将得到提高。


磁盘:1.寻址:ms(毫秒) 2.磁盘带宽:MB/s

内存:1.寻址:ns(纳秒) 2. 内存带宽:GB/s

磁盘比内存在寻址上慢了 10W 倍,传输带宽上慢了 20 倍。


开源的带缓冲区的logrus日志写入hook,就利用了 bufio 技术。


 // 利用bufio针对原始io.Writer封装成带缓冲区的io.Writer   `s.writer = bufio.NewWriterSize(s.Writer, size)   ......  if len(bs) > s.writer.Available() && s.writer.Buffered() > 0 {    if err := s.writer.Flush(); err != nil {      return err    }  }  _, err = s.writer.Write(bs)` 
复制代码

优化总结

  • sync.Pool 复用临时对象,减少 gc 次数

  • bufio利用缓冲区,减少频繁的系统调用


研发人员历来都是公司的成本大头,技术优化虽然不能增效,但是能降本,减少核数和内存条,希望大家都能通过技术优化让自己不被优化。

用户头像

急性子,入戏慢。 2018-06-17 加入

阿里云社区专家博主,同程旅行基础架构 ; 热衷分享,执着于阅读写作,佛系不水文,有态度公众号:《精益码农》; 持续输出高价值Go、.NET、云原生原创文章。

评论

发布
暂无评论
技术优化:降本增效的常规实践_有态度的马甲_InfoQ写作社区