You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
if you already know max number of byte array needed,
you could preallocate it to enhance performance:
package utils
import (
"reflect"
"sync/atomic"
"unsafe"
)
// BytePool is used to concurrently obtain byte arrays of size cap.
type BytePool struct {
i atomic.Int64
caches [][]byte
used []atomic.Bool
head uintptr
cap int
}
// NewBytePool creates a byte array pool with max byte arrays, each with a capacity of cap.
// If sync.Pool is used, at least 24 bytes of memory will be allocated each time,
// see https://blog.mike.norgate.xyz/unlocking-go-slice-performance-navigating-sync-pool-for-enhanced-efficiency-7cb63b0b453e.
// By using the space-for-time method, zero memory allocation can be achieved.
// Here, a large byte array is first allocated, and then it is divided into small byte arrays.
// The address difference between the small byte arrays is the same.
// For each byte array, an atomic.Bool is used to determine whether it is in use.
// If it is false, it means it is not in use, and it is converted to true and returned to the caller;
// if it is true, it means it has been used.
// When the byte array is used,
// we find the corresponding atomic.Bool by the difference between its address and the first address of the large byte array,
// and then set it to false.
func NewBytePool(cap, max int) *BytePool {
data := make([]byte, cap*max)
caches := make([][]byte, max)
for i := range caches {
caches[i] = data[i*cap : (i+1)*cap][:0]
}
rt := (*reflect.SliceHeader)(unsafe.Pointer(&data))
return &BytePool{
caches: caches,
used: make([]atomic.Bool, max),
head: rt.Data,
cap: cap,
}
}
// Get byte array from pool.
func (b *BytePool) Get() []byte {
for {
cur := b.i.Add(1)
if cur >= int64(len(b.caches)) {
cur = 0
b.i.Store(0)
}
if b.used[cur].CompareAndSwap(false, true) {
return b.caches[cur][:0]
}
}
}
// Put the data back into the BytePool.
func (b *BytePool) Put(x []byte) {
rt := (*reflect.SliceHeader)(unsafe.Pointer(&x))
i := int(rt.Data-b.head) / b.cap
b.used[i].Store(false)
}
The text was updated successfully, but these errors were encountered:
if you already know max number of byte array needed,
you could preallocate it to enhance performance:
The text was updated successfully, but these errors were encountered: