new package slicebytepool

pull/2/head
q191201771 5 years ago
parent fd716a0960
commit 36ddcfdb64

@ -28,5 +28,6 @@ cd ${ROOT_DIR}/demo/add_go_license && go build -ldflags "$LDFlags" -o ${ROOT_DIR
cd ${ROOT_DIR}/demo/taskpool && go build -ldflags "$LDFlags" -o ${ROOT_DIR}/bin/taskpool &&
cd ${ROOT_DIR}/demo/bufferpool && go build -ldflags "$LDFlags" -o ${ROOT_DIR}/bin/bufferpool &&
cd ${ROOT_DIR}/demo/samefile && go build -ldflags "$LDFlags" -o ${ROOT_DIR}/bin/samefile &&
cd ${ROOT_DIR}/demo/slicebytepool && go build -ldflags "$LDFlags" -o ${ROOT_DIR}/bin/slicebytepool &&
ls -lrt ${ROOT_DIR}/bin &&
echo 'build done.'

@ -0,0 +1,142 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package main
import (
"flag"
"fmt"
"math/rand"
"os"
"runtime"
"runtime/pprof"
"sync"
"sync/atomic"
"time"
"github.com/q191201771/naza/pkg/slicebytepool"
"github.com/q191201771/naza/pkg/nazalog"
)
var bp slicebytepool.SliceBytePool
//var count int32
var doneCount uint32
var tmpSliceByte []byte
var gorutineNum = 1000
var loopNum = 1000
var sleepMSec = time.Duration(10) * time.Millisecond
func size() int {
return random(1, 256*1024)
//return 128 * 1024
//ss := []int{1000, 2000, 5000}
//////ss := []int{128, 1024, 4096, 16384}
//atomic.AddInt32(&count, 1)
//return ss[count % 3]
//count++
//if count > 128 * 1024 {
// count = 1
//}
//return count
}
func random(l, r int) int {
return l + (rand.Int() % (r - l))
}
func originFunc() {
size := size()
buf := make([]byte, size)
tmpSliceByte = buf
atomic.AddUint32(&doneCount, 1)
time.Sleep(sleepMSec)
}
func bufferPoolFunc() {
size := size()
buf := bp.Get(size)
tmpSliceByte = buf
time.Sleep(sleepMSec)
bp.Put(buf)
atomic.AddUint32(&doneCount, 1)
}
func main() {
strategy := parseFlag()
nazalog.Debugf("strategy: %d", strategy)
//cpufd, err := os.Create("/tmp/cpu.prof")
//nazalog.FatalIfErrorNotNil(err)
//pprof.StartCPUProfile(cpufd)
//defer pprof.StopCPUProfile()
rand.Seed(time.Now().Unix())
if strategy != 3 {
bp = slicebytepool.NewSliceBytePool(slicebytepool.Strategy(strategy))
}
go func() {
for {
if strategy != 3 {
nazalog.Debugf("time. done=%d, pool=%+v", atomic.LoadUint32(&doneCount), bp.RetrieveStatus())
time.Sleep(1 * time.Second)
} else {
nazalog.Debugf("time. done=%d", atomic.LoadUint32(&doneCount))
time.Sleep(1 * time.Second)
}
}
}()
var wg sync.WaitGroup
wg.Add(gorutineNum * loopNum)
nazalog.Debug("> loop.")
for i := 0; i < gorutineNum; i++ {
go func() {
if strategy != 3 {
for j := 0; j < loopNum; j++ {
bufferPoolFunc()
wg.Done()
}
} else {
for j := 0; j < loopNum; j++ {
originFunc()
wg.Done()
}
}
}()
}
wg.Wait()
memfd, err := os.Create(fmt.Sprintf("/tmp/mem%d.prof", strategy))
nazalog.FatalIfErrorNotNil(err)
_ = pprof.WriteHeapProfile(memfd)
_ = memfd.Close()
nazalog.Debug("> GC.")
runtime.GC()
nazalog.Debug("< GC.")
if strategy != 5 {
nazalog.Debugf("%+v", bp.RetrieveStatus())
}
nazalog.Debug("< loop.")
}
func parseFlag() int {
strategy := flag.Int("t", 0, "type: 1. multi std pool 2. multi slice pool 3. origin")
flag.Parse()
if *strategy < 1 || *strategy > 3 {
flag.Usage()
os.Exit(1)
}
return *strategy
}

@ -0,0 +1,31 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package slicebytepool
var defaultPool SliceBytePool
func Get(size int) []byte {
return defaultPool.Get(size)
}
func Put(buf []byte) {
defaultPool.Put(buf)
}
func RetrieveStatus() Status {
return defaultPool.RetrieveStatus()
}
func Init(strategy Strategy) {
defaultPool = NewSliceBytePool(strategy)
}
func init() {
Init(StrategyMultiSlicePoolBucket)
}

@ -0,0 +1,60 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package slicebytepool
type SliceBytePool interface {
Get(size int) []byte
Put(buf []byte)
RetrieveStatus() Status
}
type Status struct {
getCount int64
putCount int64
hitCount int64
sizeBytes int64
}
type Strategy int
const (
StrategyMultiStdPoolBucket = iota + 1
StrategyMultiSlicePoolBucket
)
type Bucket interface {
Get(size int) []byte
Put(buf []byte)
}
func NewSliceBytePool(strategy Strategy) SliceBytePool {
var capToFreeBucket map[int]Bucket
switch strategy {
case StrategyMultiStdPoolBucket:
capToFreeBucket = make(map[int]Bucket)
for i := minSize; i <= maxSize; i <<= 1 {
capToFreeBucket[i] = NewStdPoolBucket()
}
case StrategyMultiSlicePoolBucket:
capToFreeBucket = make(map[int]Bucket)
for i := minSize; i <= maxSize; i <<= 1 {
capToFreeBucket[i] = NewSliceBucket()
}
}
return &sliceBytePool{
strategy: strategy,
capToFreeBucket: capToFreeBucket,
}
}

@ -0,0 +1,39 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package slicebytepool
import (
"sync"
)
type SliceBucket struct {
m sync.Mutex
core [][]byte
}
func NewSliceBucket() *SliceBucket {
return new(SliceBucket)
}
func (b *SliceBucket) Get(size int) []byte {
b.m.Lock()
defer b.m.Unlock()
if len(b.core) == 0 {
return nil
}
buf := b.core[len(b.core)-1]
b.core = b.core[:len(b.core)-1]
return buf[0:size]
}
func (b *SliceBucket) Put(buf []byte) {
b.m.Lock()
defer b.m.Unlock()
b.core = append(b.core, buf)
}

@ -0,0 +1,101 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package slicebytepool
import (
"sync/atomic"
)
var (
minSize = 1024
maxSize = 1073741824
)
type sliceBytePool struct {
strategy Strategy
capToFreeBucket map[int]Bucket
status Status
}
func (bp *sliceBytePool) Get(size int) []byte {
atomic.AddInt64(&bp.status.getCount, 1)
ss := up2power(size)
if ss < minSize {
ss = minSize
}
bucket := bp.capToFreeBucket[ss]
buf := bucket.Get(size)
if buf == nil {
buf = make([]byte, size, ss)
return buf
}
atomic.AddInt64(&bp.status.hitCount, 1)
atomic.AddInt64(&bp.status.sizeBytes, int64(-cap(buf)))
return buf
}
func (bp *sliceBytePool) Put(buf []byte) {
c := cap(buf)
atomic.AddInt64(&bp.status.putCount, 1)
atomic.AddInt64(&bp.status.sizeBytes, int64(c))
size := down2power(c)
if size < minSize {
size = minSize
}
bucket := bp.capToFreeBucket[size]
bucket.Put(buf)
}
func (bp *sliceBytePool) RetrieveStatus() Status {
return Status{
getCount: atomic.LoadInt64(&bp.status.getCount),
putCount: atomic.LoadInt64(&bp.status.putCount),
hitCount: atomic.LoadInt64(&bp.status.hitCount),
sizeBytes: atomic.LoadInt64(&bp.status.sizeBytes),
}
}
// @return 范围为 [2, 4, 8, 16, ..., 1073741824]如果大于等于1073741824则直接返回n
func up2power(n int) int {
if n >= maxSize {
return n
}
var i uint32
for ; n > (2 << i); i++ {
}
return 2 << i
}
// @return 范围为 [2, 4, 8, 16, ..., 1073741824]
func down2power(n int) int {
if n < 2 {
return 2
} else if n >= maxSize {
return maxSize
}
var i uint32
for {
nn := 2 << i
if n > nn {
i++
} else if n == nn {
return n
} else if n < nn {
return 2 << (i - 1)
}
}
}

@ -0,0 +1,36 @@
// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/naza
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package slicebytepool
import (
"sync"
)
type StdPoolBucket struct {
core *sync.Pool
}
func NewStdPoolBucket() *StdPoolBucket {
return &StdPoolBucket{
core: new(sync.Pool),
}
}
func (b *StdPoolBucket) Get(size int) []byte {
v := b.core.Get()
if v == nil {
return nil
}
vv := v.([]byte)
return vv[0:size]
}
func (b *StdPoolBucket) Put(buf []byte) {
b.core.Put(buf)
}
Loading…
Cancel
Save