2013-06-24 98 views
2

有没有某种方式可以在Go中分配未初始化的slice?频繁的模式是创建一个给定大小的片段作为缓冲区,然后仅将其中的一部分用于receive数据。例如:分配未初始化片

b := make([]byte, 0x20000) // b is zero initialized 
n, err := conn.Read(b) 
// do stuff with b[:n]. all of b is zeroed for no reason 

时,正在分配大量的缓冲区,为spec指出它会默认初始化上分配数组初始化这就会增加。

回答

0

从技术上讲,您可以通过在运行时间外分配内存并使用unsafe.Pointer,但这绝对是错误的做法。

更好的解决方案是减少分配数量。将缓冲区移到循环之外,或者,如果需要每个goroutine缓冲区,则将其中的几个分配给一个池,并只在需要时分配更多。

type BufferPool struct { 
    Capacity int 
    buffersize int 
    buffers []byte 
    lock sync.Mutex 
} 

func NewBufferPool(buffersize int, cap int) { 
    ret := new(BufferPool) 
    ret.Capacity = cap 
    ret.buffersize = buffersize 
    return ret 
} 

func (b *BufferPool) Alloc() []byte { 
    b.lock.Lock() 
    defer b.lock.Unlock() 
    if len(b.buffers) == 0 { 
     return make([]byte, b.buffersize) 
    } else { 
     ret := b.buffers[len(b.buffers) - 1] 
     b.buffers = b.buffers[0:len(b.buffers) - 1] 
     return ret 
    } 
} 

func (b *BufferPool) Free(buf []byte) { 
    if len(buf) != b.buffersize { 
     panic("illegal free") 
    } 
    b.lock.Lock() 
    defer b.lock.Unlock() 
    if len(b.buffers) < b.Capacity { 
     b.buffers = append(b.buffers, buf) 
    } 
} 
+0

另请注意,在该示例中,忘记在缓冲区中调用Free会导致它仅收集垃圾并且未添加回池中,因此不会泄漏。 – cthom06

+0

您是否应该使用缓冲通道来存储您释放的缓冲区? –

+0

@MattJoiner你可以这样做,但你仍然需要一个锁来安全地检查有多少物品被缓冲,所以你只是锁定两次,或者不检查长度,但你会泄漏goroutines,因为你会总是有(peak_use - capacity)goroutines等待推送到频道。 – cthom06

2

你可以得到非归零字节的缓冲区从bufs.Cache.Get(或见CCache的并发安全版本)。从docs

注:通过获取不能保证返回的缓冲区将被归零。没关系,例如将缓冲区传递给io.Reader。如果您需要使用Cget的零缓冲区。