The example code below is shown how pool works simply.
package main
import (
"fmt"
"math/rand"
"runtime"
"sync"
)
type Data struct {
tag string
buffer []int
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
pool := sync.Pool{
New: func() interface{} {
data := new(Data)
data.tag = "new"
data.buffer = make([]int, 10)
return data
},
}
wg := new(sync.WaitGroup)
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
data := pool.Get().(*Data)
for index := range data.buffer {
data.buffer[index] = rand.Intn(100)
}
fmt.Println(data)
data.tag = "used"
pool.Put(data)
}()
}
wg.Wait()
fmt.Println("done")
for i := 0; i < 3; i++ {
data := pool.Get().(*Data)
fmt.Println(data)
}
fmt.Scanln()
}
And run this code then give some random data structure like:
❯ go run pool.go
&{new [81 87 47 59 81 18 25 40 56 0]}
&{new [94 11 62 89 28 74 11 45 37 6]}
&{new [95 66 28 58 47 47 87 88 90 15]}
done &{used [95 66 28 58 47 47 87 88 90 15]} &{new [0 0 0 0 0 0 0 0 0 0]} &{used [94 11 62 89 28 74 11 45 37 6]}
At this point, Get() function returns randomly. it means that no guarantee returning data in the pool.
Consequently, Sync.pool guarantee simultaneous access but no provide choice of data what I want.
So this is my thought about Sync.pool.
But, I don’t know practically use case. can you give some guide or experiences?
A pool is not meant to be used as a buffer you control, it exists as a performance optimisation for you to use to reduce load on the garabge collector for frequently heap allocated objects. The godoc provides a good explanation for Pool:
A Pool is a set of temporary objects that may be individually saved and retrieved.
Any item stored in the Pool may be removed automatically at any time without notification. If the Pool holds the only reference when this happens, the item might be deallocated.
A Pool is safe for use by multiple goroutines simultaneously.
Pool’s purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. That is, it makes it easy to build efficient, thread-safe free lists. However, it is not suitable for all free lists.
An appropriate use of a Pool is to manage a group of temporary items silently shared among and potentially reused by concurrent independent clients of a package. Pool provides a way to amortize allocation overhead across many clients.
An example of good use of a Pool is in the fmt package, which maintains a dynamically-sized store of temporary output buffers. The store scales under load (when many goroutines are actively printing) and shrinks when quiescent.
On the other hand, a free list maintained as part of a short-lived object is not a suitable use for a Pool, since the overhead does not amortize well in that scenario. It is more efficient to have such objects implement their own free list.
A Pool must not be copied after first use.
The part I bolded is of note to you, it would be why sometimes the Pool doesn’t return you an object that you’ve Put back into the pool, and instead returns a brand new one, causing the behaviour you describe as random.