Skip to content

Commit ad98bea

Browse files
authored
动态评估bytes.Buffer的需求的容量,全局共享bytes.Buffer池 (#16)
* 实现动态容量和全局共享的bytes.Buffer池,相较于固定容量性能提升30倍 * 简化join int系列方法,采用动态容量bytes.Buffer池
1 parent b27a4fe commit ad98bea

File tree

6 files changed

+476
-114
lines changed

6 files changed

+476
-114
lines changed

exstrings/join_int.go

Lines changed: 47 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -9,144 +9,87 @@ import (
99
"github.com/thinkeridea/go-extend/pool"
1010
)
1111

12-
var buffPool = pool.GetBuff64()
12+
var buffPool = pool.NewBuffer(64)
1313

1414
// JoinInts 使用 sep 连接 []int 并返回连接的字符串
15-
func JoinInts(i []int, sep string) string {
16-
buf := buffPool.Get()
17-
for _, v := range i {
18-
if buf.Len() > 0 {
19-
buf.WriteString(sep)
20-
}
21-
buf.WriteString(strconv.FormatInt(int64(v), 10))
22-
}
23-
24-
buffPool.Put(buf)
25-
return buf.String()
15+
func JoinInts(v []int, sep string) string {
16+
return joinInts(len(v), sep, func(i int) string {
17+
return strconv.FormatInt(int64(v[i]), 10)
18+
})
2619
}
2720

2821
// JoinInt8s 使用 sep 连接 []int8 并返回连接的字符串
29-
func JoinInt8s(i []int8, sep string) string {
30-
buf := buffPool.Get()
31-
for _, v := range i {
32-
if buf.Len() > 0 {
33-
buf.WriteString(sep)
34-
}
35-
buf.WriteString(strconv.FormatInt(int64(v), 10))
36-
}
37-
38-
buffPool.Put(buf)
39-
return buf.String()
22+
func JoinInt8s(v []int8, sep string) string {
23+
return joinInts(len(v), sep, func(i int) string {
24+
return strconv.FormatInt(int64(v[i]), 10)
25+
})
4026
}
4127

4228
// JoinInt16s 使用 sep 连接 []int16 并返回连接的字符串
43-
func JoinInt16s(i []int16, sep string) string {
44-
buf := buffPool.Get()
45-
for _, v := range i {
46-
if buf.Len() > 0 {
47-
buf.WriteString(sep)
48-
}
49-
buf.WriteString(strconv.FormatInt(int64(v), 10))
50-
}
51-
52-
buffPool.Put(buf)
53-
return buf.String()
29+
func JoinInt16s(v []int16, sep string) string {
30+
return joinInts(len(v), sep, func(i int) string {
31+
return strconv.FormatInt(int64(v[i]), 10)
32+
})
5433
}
5534

5635
// JoinInt32s 使用 sep 连接 []int32 并返回连接的字符串
57-
func JoinInt32s(i []int32, sep string) string {
58-
buf := buffPool.Get()
59-
for _, v := range i {
60-
if buf.Len() > 0 {
61-
buf.WriteString(sep)
62-
}
63-
buf.WriteString(strconv.FormatInt(int64(v), 10))
64-
}
65-
66-
buffPool.Put(buf)
67-
return buf.String()
36+
func JoinInt32s(v []int32, sep string) string {
37+
return joinInts(len(v), sep, func(i int) string {
38+
return strconv.FormatInt(int64(v[i]), 10)
39+
})
6840
}
6941

7042
// JoinInt64s 使用 sep 连接 []int64 并返回连接的字符串
71-
func JoinInt64s(i []int64, sep string) string {
72-
buf := buffPool.Get()
73-
for _, v := range i {
74-
if buf.Len() > 0 {
75-
buf.WriteString(sep)
76-
}
77-
buf.WriteString(strconv.FormatInt(v, 10))
78-
}
79-
80-
buffPool.Put(buf)
81-
return buf.String()
43+
func JoinInt64s(v []int64, sep string) string {
44+
return joinInts(len(v), sep, func(i int) string {
45+
return strconv.FormatInt(v[i], 10)
46+
})
8247
}
8348

8449
// JoinUints 使用 sep 连接 []uint 并返回连接的字符串
85-
func JoinUints(i []uint, sep string) string {
86-
buf := buffPool.Get()
87-
for _, v := range i {
88-
if buf.Len() > 0 {
89-
buf.WriteString(sep)
90-
}
91-
buf.WriteString(strconv.FormatUint(uint64(v), 10))
92-
}
93-
94-
buffPool.Put(buf)
95-
return buf.String()
50+
func JoinUints(v []uint, sep string) string {
51+
return joinInts(len(v), sep, func(i int) string {
52+
return strconv.FormatUint(uint64(v[i]), 10)
53+
})
9654
}
9755

9856
// JoinUint8s 使用 sep 连接 []uint8 并返回连接的字符串
99-
func JoinUint8s(i []uint8, sep string) string {
100-
buf := buffPool.Get()
101-
for _, v := range i {
102-
if buf.Len() > 0 {
103-
buf.WriteString(sep)
104-
}
105-
buf.WriteString(strconv.FormatUint(uint64(v), 10))
106-
}
107-
108-
buffPool.Put(buf)
109-
return buf.String()
57+
func JoinUint8s(v []uint8, sep string) string {
58+
return joinInts(len(v), sep, func(i int) string {
59+
return strconv.FormatUint(uint64(v[i]), 10)
60+
})
11061
}
11162

11263
// JoinUint16s 使用 sep 连接 []uint16 并返回连接的字符串
113-
func JoinUint16s(i []uint16, sep string) string {
114-
buf := buffPool.Get()
115-
for _, v := range i {
116-
if buf.Len() > 0 {
117-
buf.WriteString(sep)
118-
}
119-
buf.WriteString(strconv.FormatUint(uint64(v), 10))
120-
}
121-
122-
buffPool.Put(buf)
123-
return buf.String()
64+
func JoinUint16s(v []uint16, sep string) string {
65+
return joinInts(len(v), sep, func(i int) string {
66+
return strconv.FormatUint(uint64(v[i]), 10)
67+
})
12468
}
12569

12670
// JoinUint32s 使用 sep 连接 []uint32 并返回连接的字符串
127-
func JoinUint32s(i []uint32, sep string) string {
128-
buf := buffPool.Get()
129-
for _, v := range i {
130-
if buf.Len() > 0 {
131-
buf.WriteString(sep)
132-
}
133-
buf.WriteString(strconv.FormatUint(uint64(v), 10))
134-
}
135-
136-
buffPool.Put(buf)
137-
return buf.String()
71+
func JoinUint32s(v []uint32, sep string) string {
72+
return joinInts(len(v), sep, func(i int) string {
73+
return strconv.FormatUint(uint64(v[i]), 10)
74+
})
13875
}
13976

14077
// JoinUint64s 使用 sep 连接 []uint64 并返回连接的字符串
141-
func JoinUint64s(i []uint64, sep string) string {
78+
func JoinUint64s(v []uint64, sep string) string {
79+
return joinInts(len(v), sep, func(i int) string {
80+
return strconv.FormatUint(v[i], 10)
81+
})
82+
}
83+
84+
func joinInts(n int, sep string, f func(i int) string) string {
14285
buf := buffPool.Get()
143-
for _, v := range i {
86+
defer buffPool.Put(buf)
87+
for i := 0; i < n; i++ {
14488
if buf.Len() > 0 {
14589
buf.WriteString(sep)
14690
}
147-
buf.WriteString(strconv.FormatUint(v, 10))
91+
buf.WriteString(f(i))
14892
}
14993

150-
buffPool.Put(buf)
15194
return buf.String()
15295
}

pool/benchmark/buffer_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package benchmark
2+
3+
import (
4+
"bytes"
5+
"container/ring"
6+
"math/rand"
7+
"sync"
8+
"testing"
9+
10+
"github.com/thinkeridea/go-extend/pool"
11+
)
12+
13+
var bufferData = ring.New(256)
14+
15+
func init() {
16+
data := bufferData
17+
for i := 0; i < 256; i++ {
18+
data.Value = make([]byte, rand.Intn(1<<16))
19+
data = data.Next()
20+
}
21+
}
22+
23+
func BenchmarkBufferPool(b *testing.B) {
24+
buff := pool.NewBuffer(64)
25+
p := [20]*bytes.Buffer{}
26+
data := bufferData
27+
for i := 0; i < b.N; i++ {
28+
data.Next()
29+
bf := buff.Get()
30+
bf.Write(data.Value.([]byte))
31+
32+
idx := i % 20
33+
if v := p[idx]; v != nil {
34+
buff.Put(v)
35+
}
36+
37+
p[idx] = bf
38+
}
39+
}
40+
41+
func BenchmarkBufferSyncPool(b *testing.B) {
42+
buff := sync.Pool{New: func() interface{} {
43+
return bytes.NewBuffer(make([]byte, 0, 64))
44+
}}
45+
46+
p := [20]*bytes.Buffer{}
47+
data := bufferData
48+
for i := 0; i < b.N; i++ {
49+
data.Next()
50+
bf := buff.Get().(*bytes.Buffer)
51+
bf.Write(data.Value.([]byte))
52+
53+
idx := i % 20
54+
if v := p[idx]; v != nil {
55+
buff.Put(v)
56+
}
57+
58+
p[idx] = bf
59+
}
60+
}
61+
62+
// 用来测试在容量没有变化的情况下与原始方式的性能差异
63+
func BenchmarkBufferFixedSizePool(b *testing.B) {
64+
buff := pool.NewBuffer(64)
65+
p := [20]*bytes.Buffer{}
66+
data := make([]byte, 50)
67+
for i := 0; i < b.N; i++ {
68+
bf := buff.Get()
69+
bf.Write(data)
70+
71+
idx := i % 20
72+
if v := p[idx]; v != nil {
73+
buff.Put(v)
74+
}
75+
76+
p[idx] = bf
77+
}
78+
}
79+
80+
func BenchmarkBufferFixedSizeSyncPool(b *testing.B) {
81+
buff := sync.Pool{New: func() interface{} {
82+
return bytes.NewBuffer(make([]byte, 0, 64))
83+
}}
84+
85+
p := [20]*bytes.Buffer{}
86+
data := make([]byte, 50)
87+
for i := 0; i < b.N; i++ {
88+
bf := buff.Get().(*bytes.Buffer)
89+
bf.Write(data)
90+
91+
idx := i % 20
92+
if v := p[idx]; v != nil {
93+
buff.Put(v)
94+
}
95+
96+
p[idx] = bf
97+
}
98+
}

0 commit comments

Comments
 (0)