-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
148 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,33 @@ | ||
# gpool | ||
Generic Pool in Go | ||
Generic wrapper for sync.Pool in Go | ||
|
||
## Usage | ||
|
||
`int64` type | ||
```go | ||
p := Pool[int64]{New: func() int64 { return 42 }} | ||
x := p.Get() | ||
defer p.Put(x) | ||
fmt.Printf("x = (%T) %d", x, x) | ||
// Output: x = (int64) 42 | ||
``` | ||
|
||
`string` type | ||
```go | ||
p := Pool[string]{New: func() string { return "foo" }} | ||
x := p.Get() | ||
defer p.Put(x) | ||
fmt.Printf("x = (%T) %s", x, x) | ||
// Output: x = (string) foo | ||
``` | ||
|
||
## Benchmarks | ||
|
||
```shell | ||
% go test -bench=. -benchmem ./... | ||
goos: darwin | ||
goarch: arm64 | ||
pkg: github.com/sv-tools/gpool | ||
BenchmarkSyncPool-8 699275571 1.614 ns/op 0 B/op 0 allocs/op | ||
BenchmarkPool-8 647708158 1.732 ns/op 0 B/op 0 allocs/op | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package gpool | ||
|
||
import "sync" | ||
|
||
// Pool is generic drop-in replacement of `sync.Pool` | ||
type Pool[T any] struct { | ||
sp sync.Pool | ||
|
||
// 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() T | ||
} | ||
|
||
// Put adds x to the pool. | ||
func (p *Pool[T]) Put(x T) { | ||
p.sp.Put(x) | ||
} | ||
|
||
// 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. | ||
func (p *Pool[T]) Get() (item T) { | ||
x := p.sp.Get() | ||
if x == nil { | ||
if p.New != nil { | ||
return p.New() | ||
} | ||
return item | ||
} | ||
return x.(T) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package gpool | ||
|
||
import ( | ||
"fmt" | ||
"math/rand" | ||
"sync" | ||
"testing" | ||
) | ||
|
||
func TestPool(t *testing.T) { | ||
p := Pool[int64]{} | ||
x := p.Get() | ||
if x != 0 { | ||
t.Fatalf("expected x = 0, but got %d", x) | ||
} | ||
p.New = func() int64 { | ||
// should return only a number which is greater than zero | ||
v := rand.Int63() | ||
for v <= 0 { | ||
v = rand.Int63() | ||
} | ||
return v | ||
} | ||
x = p.Get() | ||
if x == 0 { | ||
t.Fatal("expected x != 0, but got 0") | ||
} | ||
p.Put(-1) | ||
// getting until the pool returns -1 or fails by timeout | ||
for x != -1 { | ||
x = p.Get() | ||
} | ||
} | ||
|
||
var benchmarkSyncPoolResult any | ||
|
||
func BenchmarkSyncPool(b *testing.B) { | ||
p := sync.Pool{New: func() any { return 42 }} | ||
b.ResetTimer() | ||
b.RunParallel(func(pb *testing.PB) { | ||
var res any | ||
for pb.Next() { | ||
res = p.Get() | ||
p.Put(res) | ||
} | ||
benchmarkSyncPoolResult = res | ||
}) | ||
} | ||
|
||
var benchmarkPoolResult int64 | ||
|
||
func BenchmarkPool(b *testing.B) { | ||
p := Pool[int64]{New: func() int64 { return 42 }} | ||
b.ResetTimer() | ||
b.RunParallel(func(pb *testing.PB) { | ||
var res int64 | ||
for pb.Next() { | ||
res = p.Get() | ||
p.Put(res) | ||
} | ||
benchmarkPoolResult = res | ||
}) | ||
} | ||
|
||
func ExamplePool_int64() { | ||
p := Pool[int64]{New: func() int64 { return 42 }} | ||
x := p.Get() | ||
defer p.Put(x) | ||
fmt.Printf("x = (%T) %d", x, x) | ||
// Output: x = (int64) 42 | ||
} | ||
|
||
func ExamplePool_string() { | ||
p := Pool[string]{New: func() string { return "foo" }} | ||
x := p.Get() | ||
defer p.Put(x) | ||
fmt.Printf("x = (%T) %s", x, x) | ||
// Output: x = (string) foo | ||
} |