分配未初始化的切片

huangapple go评论69阅读模式
英文:

Allocate uninitialized slice

问题

有没有一种方法在Go中分配一个未初始化的切片?一个常见的模式是创建一个给定大小的切片作为缓冲区,然后只使用其中的一部分来接收数据。例如:

b := make([]byte, 0x20000) // b是零初始化的
n, err := conn.Read(b)
// 使用b[:n]进行操作。整个b都被无缘无故地清零了

当大量的缓冲区被分配时,这种初始化会累积起来,因为规范指出它会在分配时默认初始化数组。

英文:

Is there some way to allocate an uninitialized slice in Go? A frequent pattern is to create a slice of a given size as a buffer, and then only use part of it to receive data. For example:

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

This initialization can add up when lots of buffers are being allocated, as the spec states it will default initialize the array on allocation.

答案1

得分: 2

你可以从bufs.Cache.Get获取非零字节缓冲区(或者查看CCache以获取并发安全版本)。根据文档

> 注意:通过Get返回的缓冲区不能保证是零值。这对于将缓冲区传递给io.Reader是可以的。如果你需要一个零值缓冲区,请使用Cget。

英文:

You can get non zeroed byte buffers from bufs.Cache.Get (or see CCache for the concurrent safe version). From the docs:

> NOTE: The buffer returned by Get is not guaranteed to be zeroed. That's okay for e.g. passing a buffer to io.Reader. If you need a zeroed buffer use Cget.

答案2

得分: 0

Technically you could by allocating the memory outside the go runtime and using unsafe.Pointer, but this is definitely the wrong thing to do.

A better solution is to reduce the number of allocations. Move buffers outside loops, or, if you need per goroutine buffers, allocate several of them in a pool and only allocate more when they're needed.

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)
    }
}
英文:

Technically you could by allocating the memory outside the go runtime and using unsafe.Pointer, but this is definitely the wrong thing to do.

A better solution is to reduce the number of allocations. Move buffers outside loops, or, if you need per goroutine buffers, allocate several of them in a pool and only allocate more when they're needed.

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(&quot;illegal free&quot;)
	}
	b.lock.Lock()
	defer b.lock.Unlock()
	if len(b.buffers) &lt; b.Capacity {
		b.buffers = append(b.buffers, buf)
	}
}

huangapple
  • 本文由 发表于 2013年6月24日 20:47:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/17275863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定