Sync. Pool Usage scenario

Save and reuse temporary objects, reducing memory allocation and GC stress

example

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)
}
Copy the code

Json deserialization is very common in the process of text parsing and network communication. When the program concurrency is very high, a large number of temporary variables need to be created in a short time, and these objects are allocated on the heap, which will cause great pressure to GC and seriously affect the performance of the program.

Sync. Pool is scalable and concurrency safe and is limited by memory size. Sync. Pool is used to store values that are allocated but not used, but may be used in the future. In this way, you do not need to allocate memory again and improve efficiency.

Sync. Pool is scalable and dynamically expanded when the load is high. Objects stored in the Pool are automatically cleared when they become inactive.

How to use

Declare an object pool

As long as the New function is implemented, there are no objects in the object pool, then the New function is called to create

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

Get& Put


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

Copy the code
  • Get() is used to Get an object from the object pool because interface{} therefore requires a value type conversion when returning a value
  • Put() will pool objects after they are used up

Struct performance test

package sync import ( "encoding/json" "sync" "testing" ) type Student struct { Name string Age int32 Remark [1024]byte }  var studentPool = sync.Pool{New: func() interface{} { return new(Student) }} var buf, _ = json.Marshal(Student{Name: "Geektutu", Age: 25}) 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) } }Copy the code

Execute the command

 go test -bench . -benchmem
Copy the code

The execution result is as follows:

goos: darwin goarch: amd64 pkg: code.byted.org/wangmingming.hit/GoProject/main/gobase/sync cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60ghz BenchmarkUnmarshal-12 13280 94006 NS/OP 1384 B/ OP 7 Allocs/OP BenchmarkUnmarshalWithPool-12 12662 95211 ns/op 232 B/op 6 allocs/op PASSCopy the code

BenchmarkUnmarshal took 94006 nanoseconds per cycle,

Results the item meaning
BenchmarkUnmarshal-12 BenchmarkUnmarshalIs the name of the function being tested– 12Indicates that the value of GOMAXPROCS (number of threads) is 12
13280 That means all of them have been executed13280Time, that is,b.NThe value of the
94006.0 ns/op Represents the average cost per operation94006.0 nanoseconds
1384/op Indicates that each operation is applied1384 ByteMemory allocation for
7 allocs/op Indicates that each operation is applied7Time memory

You can see that after sync.Pool is used, the memory usage is only 232/1384 unused.

The resources

  • Geektutu.com/post/hpg-sy…
  • Geektutu.com/post/high-p…
  • Github.com/wangxiaomin…
  • Geektutu.com/post/qa-gol…