Go性能优化:sync包的使用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 一、Sync.pool的使用
    • Sync.pool 使用示例
    • Sync.pool 性能测试
      • `struct 反序列化`
      • 性能测试结果:sync.pool内存节省了几倍
    • sync.pool 使用案例1:Json序列化减少内存分配
      • bytes.Buffer性能测试
      • bytes.buffer使用sync.pool优化结果:速度提高16倍,内存分配为0
      • 再结合Go stringsToByte和byteToString优化, 性能得到客观的提升


Go性能优化:sync包的使用_第1张图片

一、Sync.pool的使用

主治功效:保存和复用临时对象,减少内存分配,降低 GC 压力。

Sync.pool 使用示例

var studentPool = sync.Pool{
    New: func() interface{} { 
        return new(Student) 
    },
}

stu := studentPool.Get().(*Student)
json.Unmarshal(buf, stu)
studentPool.Put(stu)

  • Get() 用于从对象池中获取对象,因为返回值是 interface{},因此需要类型转换。
  • Put() 则是在对象使用完毕后,返回对象池。

json 的反序列化在文本解析和网络通信过程中非常常见,当程序并发度非常高的情况下,短时间内需要创建大量的临时对象。而这些对象是都是分配在堆上的,会给 GC 造成很大压力,严重影响程序的性能

Go 语言从 1.3 版本开始提供了对象重用的机制,即 sync.Pool。sync.Pool 是可伸缩的,同时也是并发安全的,其大小仅受限于内存的大小。sync.Pool 用于存储那些被分配了但是没有被使用,而未来可能会使用的值。这样就可以不用再次经过内存分配,可直接复用已有对象,减轻 GC 的压力,从而提升系统的性能。

sync.Pool 的大小是可伸缩的,高负载时会动态扩容,存放在池中的对象如果不活跃了会被自动清理。

Sync.pool 性能测试

struct 反序列化

func BenchmarkUnmarshal(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stu := &Student{}
		json.Unmarshal(buf, stu)
	}
}

func BenchmarkUnmarshalWithPool(b *testing.B) {
	for n := 0; n < b.N; n++ {
		stu := studentPool.Get().(*Student)
		json.Unmarshal(buf, stu)
		studentPool.Put(stu)
	}
}

性能测试结果:sync.pool内存节省了几倍

➜  pkg go test -bench . -benchmem
goos: linux
goarch: amd64
cpu: Intel(R) Core(TM) i5-8500 CPU @ 3.00GHz
BenchmarkUnmarshal-6               12548             94582 ns/op            1400 B/op          8 allocs/op
BenchmarkUnmarshalWithPool-6       12656             97219 ns/op             248 B/op          7 allocs/op
PASS
ok      exinterface/pkg 4.348s

sync.pool 使用案例1:Json序列化减少内存分配

type Student struct {
	Name   string
	Age    int32
	Remark [1024]byte
}

var buf, _ = json.Marshal(Student{Name: "Geektutu", Age: 25})

func unmarsh() {
	stu := &Student{}
	json.Unmarshal(buf, stu)
}

bytes.Buffer性能测试

var bufferPool = sync.Pool{
	New: func() interface{} {
		return &bytes.Buffer{}
	},
}

var data = make([]byte, 10000)

func BenchmarkBufferWithPool(b *testing.B) {
	for n := 0; n < b.N; n++ {
		buf := bufferPool.Get().(*bytes.Buffer)
		buf.Write(data)
		buf.Reset()
		bufferPool.Put(buf)
	}
}

func BenchmarkBuffer(b *testing.B) {
	for n := 0; n < b.N; n++ {
		var buf bytes.Buffer
		buf.Write(data)
	}
}

bytes.buffer使用sync.pool优化结果:速度提高16倍,内存分配为0

➜  pkg go test -bench . -benchmem
goos: linux
goarch: amd64

cpu: Intel(R) Core(TM) i5-8500 CPU @ 3.00GHz
BenchmarkBufferWithPool-6       11722344               102.3 ns/op             0 B/op          0 allocs/op
BenchmarkBuffer-6                 753886              1639 ns/op           10240 B/op          1 allocs/op
PASS
ok      exinterface/pkg 2.563s

再结合Go stringsToByte和byteToString优化, 性能得到客观的提升

// StringToBytes converts string to byte slice without a memory allocation.
func StringToBytes(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(
		&struct {
			string
			Cap int
		}{s, len(s)},
	))
}

var (
	p sync.Pool
)

// BytesToString converts byte slice to string without a memory allocation.
func BytesToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

你可能感兴趣的:(L0:计算机,#,L1:编程语言,golang,性能优化)