栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在Golang中实现内存池

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在Golang中实现内存池

事先注意:

许多人建议

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 pooldefault: // All in use, create a new, temporary:    bo = &BigObject{Id:-1}}

在这种情况下,您无需将其放回池中。或者,如果池中有空间,则可以选择再次尝试将所有内容放回池中,而不会阻塞

select

select {case pool <- bo: // Try to put back into the pooldefault: // Pool is full, will be garbage collected}

笔记:

预先填充池是可选的。如果

select
用于尝试从池中获取值/将值放回池中,则池最初可能是空的。

您必须确保您不会在请求之间泄漏信息,例如,请确保您没有在共享对象中使用已设置并属于其他请求的字段和值。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/447936.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号