Go 如何正确使用sync.pool进行切片

Go 如何正确使用sync.pool进行切片,go,Go,我正在构建一个Go应用程序来服务数千个HTTP请求。服务包括解析输入、处理输入和返回输出 输入解析包括将json解析为map[string]string 如何实现此解析的内存池 最小可复制示例: var poolTest *sync.Pool func init() { poolTest = &sync.Pool{ New: func() interface{} { return new([]map[string]string)

我正在构建一个Go应用程序来服务数千个HTTP请求。服务包括解析输入、处理输入和返回输出

输入解析包括将
json
解析为
map[string]string

如何实现此解析的内存池

最小可复制示例:

var poolTest *sync.Pool

func init() {
    poolTest = &sync.Pool{
        New: func() interface{} {
            return new([]map[string]string)
        },
    }
}

func Requesthandler (ctx *fasthttp.RequestCtx) {
    poolTestList  := poolTest.Get().(*[]map[string]string)
    input := ctx.PostBody()
    _=json.Unmarshal(input, poolTestList)

    //do something
    print(*(poolTestList))
   
     //clear and return to pool
    (*poolTestList) = (*poolTestList)[:0]
    poolTest.Put(poolTestList)
}

func main() {
    _ = (&fasthttp.Server{
        Handler:        Requesthandler,
        ReadBufferSize: 8192,
        TCPKeepalive: true,
    }).ListenAndServe(":3000")
}
我感到困惑的部分是清理和返回游泳池


这是正确的方法吗?

您的实现通常是正确的,但是这里有一些奇怪的事情。首先,几乎不需要指向切片的指针;你在这里绝对不需要。您的值应该只是
[]映射[string]字符串
而不是
*[]映射[string]字符串

其次,最佳实践是在
Get
之后重置池对象,而不是在
Put
之前。这是最安全的,因为这意味着
Get
不会对从池中接收到的值做出任何潜在的不安全假设。如果项目倾向于在池中停留很长时间并且非常大,您也可以同时执行这两种操作(这里可能会有来自地图切片的非常高的内存使用率,因此这将取决于您的用例)

需要注意的是,
//do something
中的内容可能是相关的,因为这里使用的是映射和切片,它们的行为符合引用语义。如果任何切片或映射泄漏了此方法,您可能会在无意中遇到一些潜在问题,这些问题可能很难诊断


最后,请记住,这段代码并不是汇集贴图,而是汇集切片。因此,如果这些是大型地图的短列表,那么这里的好处可能很小。事实上,即使是长长的地图列表,也可能很少。我将删除池代码、基准和配置文件,并确保您确实在优化与性能相关的内容。

您正在将
**[]映射[string]字符串
传递到
解组
,这可能不是您想要的。片分配可能不是这里的瓶颈——您已经分配了许多片,甚至可以深入到http请求中,所有数据都将在映射中,使用新分配的结构。你确定
sync.Pool
对你有任何好处吗?这根本是错误的。以正确的代码开始。如果GC压力是实际瓶颈,则进行优化。重用没有映射的切片是毫无意义的,重用map memmory是很困难的。如果GC压力是你的问题:实现你自己的json.unmarshalery你知道“数千个请求”对任何现代计算机来说都不算什么,对吗?(除非你是指每秒)这看起来很像过早优化。