Skip to content

Commit

Permalink
the code (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
SVilgelm authored May 23, 2023
1 parent 90545ea commit 2814f26
Showing 3 changed files with 148 additions and 1 deletion.
33 changes: 32 additions & 1 deletion README.md
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
```
37 changes: 37 additions & 0 deletions pool.go
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)
}
79 changes: 79 additions & 0 deletions pool_test.go
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
}

0 comments on commit 2814f26

Please sign in to comment.