-
Notifications
You must be signed in to change notification settings - Fork 0
/
chanPool.go
86 lines (81 loc) · 2.09 KB
/
chanPool.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package bufpool
import (
"bytes"
"fmt"
)
// ChanPool maintains a free-list of buffers.
type ChanPool struct {
ch chan *bytes.Buffer
pc poolConfig
}
// NewChanPool creates a new FreeList. The pool size, size of new buffers, and max size of buffers
// to keep when returned to the pool can all be customized.
//
// package main
//
// import (
// "log"
//
// "github.com/karrick/bufpool"
// )
//
// func main() {
// bp, err := bufpool.NewChanPool()
// if err != nil {
// log.Fatal(err)
// }
// for i := 0; i < 4*bufpool.DefaultPoolSize; i++ {
// go func() {
// for j := 0; j < 1000; j++ {
// bb := bp.Get()
// for k := 0; k < 3*bufpool.DefaultBufSize; k++ {
// bb.WriteByte(byte(k % 256))
// }
// bp.Put(bb)
// }
// }()
// }
// }
func NewChanPool(setters ...Configurator) (FreeList, error) {
pc := &poolConfig{
poolSize: DefaultPoolSize,
bufSize: DefaultBufSize,
maxKeep: DefaultMaxKeep,
}
for _, setter := range setters {
if err := setter(pc); err != nil {
return nil, err
}
}
if pc.maxKeep < pc.bufSize {
return nil, fmt.Errorf("max buffer size must be greater or equal to default buffer size: %d, %d", pc.maxKeep, pc.bufSize)
}
bp := &ChanPool{
ch: make(chan *bytes.Buffer, pc.poolSize),
pc: *pc,
}
return bp, nil
}
// Get returns an initialized buffer from the free-list.
func (bp *ChanPool) Get() *bytes.Buffer {
select {
case bb := <-bp.ch:
// reuse buffer
return bb
default:
// empty channel: create new buffer
return bytes.NewBuffer(make([]byte, 0, bp.pc.bufSize))
}
}
// Put will return a used buffer back to the free-list. If the capacity of the used buffer grew
// beyond the max buffer size, it will be discarded and its memory returned to the runtime.
func (bp *ChanPool) Put(bb *bytes.Buffer) {
if bb.Cap() > bp.pc.maxKeep {
return // drop buffer on floor if too big
}
bb.Reset()
select {
case bp.ch <- bb: // queue buffer for reuse
default: // drop on floor if channel full
}
}