如何在Golang中实现内存池
我在Go中实现了HTTP服务器。
对于每个请求,我需要为一个特定的结构创建数百个对象,并且我有大约10个这样的结构。因此,按照Go实现完成请求后,将对其进行垃圾回收。
因此,对于每个请求,将分配和释放大量的内存。
相反,我想实现内存池以提高分配端以及GC端的性能。
在请求开始时,我将从池中取出并在请求处理后放回去
从池实施方面
- 如何分配和取消分配特定类型结构的内存?
- 如何跟踪此内存已分配而其他内存未分配的信息?
在内存分配和释放的情况下,还有其他提高性能的建议吗?
回答:
许多人建议sync.Pool
对 临时
对象使用快速,良好的实现。但是请注意,sync.Pool
这不能保证保留合并的对象。引用其文档:
池中存储的任何项目都 。如果发生这种情况时,池中只有唯一的引用,则该项目可能会被释放。
因此,如果您不希望对象中的对象Pool
被垃圾回收(这取决于您的情况,可能会导致更多分配),那么下面介绍的解决方案会更好,因为通道缓冲区中的值不会被垃圾回收。如果您的对象确实足够大以至于有足够的内存池,则将分摊池通道的开销。
此外,sync.Pool
不允许您限制合并对象的数量,而下面提供的解决方案自然可以。
最简单的内存池“实现”是一个缓冲通道。
假设您想要一些大对象的内存池。创建一个缓冲的通道,其中包含指向此类昂贵对象的值的指针,并且在需要时,从池(通道)中接收一个。使用完后,将其放回池中(在通道上发送)。为了避免意外丢失对象(例如在发生紧急情况时),请defer
在放回它们时使用声明。
让我们将其用作大对象的类型:
type BigObject struct { Id int
Something string
}
创建一个池是:
pool := make(chan *BigObject, 10)
池的大小就是通道缓冲区的大小。
用昂贵的对象的指针填充池(这是可选的,请参阅最后的注释):
for i := 0; i < cap(pool); i++ { bo := &BigObject{Id: i}
pool <- bo
}
通过许多goroutines使用池:
wg := sync.WaitGroup{}for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
bo := <-pool
defer func() { pool <- bo }()
fmt.Println("Using", bo.Id)
fmt.Println("Releasing", bo.Id)
}()
}
wg.Wait()
在Go Playground上尝试一下。
请注意,如果所有“池”对象都在使用中,则此实现会阻塞。如果您不希望这样做,则可以select
在所有正在使用的对象上强制创建新对象:
var bo *BigObjectselect {
case bo = <-pool: // Try to get one from the pool
default: // All in use, create a new, temporary:
bo = &BigObject{Id:-1}
}
在这种情况下,您无需将其放回池中。或者,如果池中有空间,则可以选择再次尝试将所有内容放回池中,而不会阻塞select
:
select {case pool <- bo: // Try to put back into the pool
default: // Pool is full, will be garbage collected
}
预先填充池是可选的。如果select
用于尝试从池中获取值/将值放回池中,则池最初可能是空的。
您必须确保您不会在请求之间泄漏信息,例如,请确保您没有在共享对象中使用已设置并属于其他请求的字段和值。
以上是 如何在Golang中实现内存池 的全部内容, 来源链接: utcz.com/qa/426465.html