2013-06-24 63 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的零緩衝區。