Usually Get and Put are not fired on the same goroutine, which will result in a difference in the fired times of Get and Put on each P. The difference part will trigger the steal operation(using CAS).
poolLocal.private has only one.
Get/Put operations are very frequent. In most cases, Get/Put needs to operate poolLocal.shared (using CAS) instead of the lock-free poolLocal.private.
Frequent GC.
sync.Pool is designed to serve objects with a short life cycle, but we just want to reuse, don’t want frequent GC.
Optimize of syncx.Pool
Transform poolLocal.private into an array to increase the frequency of poolLocal.private use.
Batch operation poolLocal.shared, reduce CAS calls.
Allow No GC.
Not Recommended
A single object is too large.
syncx.Pool permanently holds up to runtime.GOMAXPROC(0)*256 reusable objects.
For example, under a 4-core docker, a 4KB object will cause about 4MB of memory usage.
please evaluate it yourself.
Performance
benchmark
sync ns/op
syncx ns/op
delta
BenchmarkSyncPoolParallel-4(p=16)
877
620
-29.30%
BenchmarkSyncPoolParallel-4(p=1024)
49385
33465
-32.24%
BenchmarkSyncPoolParallel-4(p=4096)
255671
149522
-41.52%
Example
var pool = &syncx.Pool{
New: func() interface{} {
return &struct{}
},
NoGC: true,
}
func getput() {
var obj = pool.Get().(*struct)
pool.Put(obj)
}
type Pool struct {
// New optionally specifies a function to generate// a value when Get would otherwise return nil.// It may not be changed concurrently with calls to Get.
New func() interface{}
// NoGC any objects in this Pool. NoGC bool// contains filtered or unexported fields
}
Get selects an arbitrary item from the Pool, removes it from the
Pool, and returns it to the caller.
Get may choose to ignore the pool and treat it as empty.
Callers should not assume any relation between values passed to Put and
the values returned by Get.
If Get would otherwise return nil and p.New is non-nil, Get returns
the result of calling p.New.