Created
February 5, 2015 21:08
-
-
Save redbo/9791719f609e63215458 to your computer and use it in GitHub Desktop.
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
package main | |
import ( | |
"fmt" | |
"runtime" | |
"sync" | |
"sync/atomic" | |
"time" | |
"unsafe" | |
) | |
// ChannelPool | |
type ChannelPool chan interface{} | |
func (f ChannelPool) Get() interface{} { | |
var v interface{} | |
select { | |
case v = <-f: | |
return v | |
default: | |
return nil | |
} | |
} | |
func (f ChannelPool) Put(v interface{}) { | |
select { | |
case f <- v: | |
default: | |
} | |
} | |
func NewChannelPool(size int) ChannelPool { | |
return make(ChannelPool, size) | |
} | |
// MutexPool | |
type MutexPool struct { | |
sync.Mutex | |
list []interface{} | |
top int | |
} | |
func (m *MutexPool) Put(v interface{}) { | |
m.Lock() | |
if m.top < len(m.list) { | |
m.list[m.top] = v | |
m.top++ | |
} | |
m.Unlock() | |
} | |
func (m *MutexPool) Get() interface{} { | |
var ret interface{} = nil | |
m.Lock() | |
if m.top > 0 { | |
ret = m.list[m.top-1] | |
m.top-- | |
} | |
m.Unlock() | |
return ret | |
} | |
func NewMutexPool(size int) *MutexPool { | |
return &MutexPool{list: make([]interface{}, size)} | |
} | |
// AtomicPool | |
type AtomicPool struct { | |
list []interface{} | |
pop []*int32 | |
} | |
func (a *AtomicPool) Get() interface{} { | |
for i, p := range a.pop { | |
if atomic.CompareAndSwapInt32(p, 2, 1) { | |
ret := a.list[i] | |
atomic.StoreInt32(p, 0) | |
return ret | |
} | |
} | |
return nil | |
} | |
func (a *AtomicPool) Put(v interface{}) { | |
for i, p := range a.pop { | |
if atomic.CompareAndSwapInt32(p, 0, 1) { | |
a.list[i] = v | |
atomic.StoreInt32(p, 2) | |
return | |
} | |
} | |
} | |
func NewAtomicPool(size int) *AtomicPool { | |
p := &AtomicPool{list: make([]interface{}, size), pop: make([]*int32, size)} | |
for i := 0; i < size; i++ { | |
p.pop[i] = new(int32) | |
} | |
return p | |
} | |
// AtomicPool2 | |
type AtomicPool2 []*unsafe.Pointer | |
func (a AtomicPool2) Get() interface{} { | |
for _, p := range a { | |
if v := atomic.SwapPointer(p, nil); v != nil { | |
return *(*interface{})(v) | |
} | |
} | |
return nil | |
} | |
func (a AtomicPool2) Put(v interface{}) { | |
vp := unsafe.Pointer(&v) | |
for _, p := range a { | |
if atomic.CompareAndSwapPointer(p, nil, vp) { | |
return | |
} | |
} | |
} | |
func NewAtomicPool2(size int) AtomicPool2 { | |
a := make(AtomicPool2, size) | |
for i := range a { | |
a[i] = new(unsafe.Pointer) | |
} | |
return a | |
} | |
// benchmarking stuff | |
type pool interface { | |
Get() interface{} | |
Put(interface{}) | |
} | |
func testpool(name string, p pool, threads int) { | |
ops := int64(0) | |
allocs := int64(0) | |
running := true | |
starterPistol := make(chan int) | |
for i := 0; i < threads; i++ { | |
go func() { | |
_, _ = <-starterPistol | |
for running { | |
if v, ok := p.Get().([]byte); ok { | |
p.Put(v) | |
} else { | |
atomic.AddInt64(&allocs, 1) | |
p.Put(make([]byte, 4096)) | |
} | |
atomic.AddInt64(&ops, 1) | |
} | |
}() | |
} | |
close(starterPistol) | |
time.Sleep(10 * time.Second) | |
running = false | |
fmt.Printf("%15s % 10d % 7d\n", name, ops, allocs) | |
runtime.GC() | |
time.Sleep(time.Second / 2) | |
runtime.GC() | |
time.Sleep(time.Second / 2) | |
} | |
func main() { | |
runtime.GOMAXPROCS(runtime.NumCPU()) | |
fmt.Printf("%15s % 10s % 7s\n", "POOL", "OPS", "ALLOCS") | |
fmt.Println() | |
fmt.Println("(8 goroutines)") | |
testpool("sync.Pool", &sync.Pool{}, 8) | |
testpool("ChannelPool", NewChannelPool(8), 8) | |
testpool("MutexPool", NewMutexPool(8), 8) | |
testpool("AtomicPool", NewAtomicPool(8), 8) | |
testpool("AtomicPool2", NewAtomicPool2(8), 8) | |
fmt.Println() | |
fmt.Println("(16 goroutines)") | |
testpool("sync.Pool", &sync.Pool{}, 16) | |
testpool("ChannelPool", NewChannelPool(8), 16) | |
testpool("MutexPool", NewMutexPool(8), 16) | |
testpool("AtomicPool", NewAtomicPool(8), 16) | |
testpool("AtomicPool2", NewAtomicPool2(8), 16) | |
fmt.Println() | |
fmt.Println("(32 goroutines)") | |
testpool("sync.Pool", &sync.Pool{}, 32) | |
testpool("ChannelPool", NewChannelPool(8), 32) | |
testpool("MutexPool", NewMutexPool(8), 32) | |
testpool("AtomicPool", NewAtomicPool(8), 32) | |
testpool("AtomicPool2", NewAtomicPool2(8), 32) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment