gpt4 book ai didi

http - 使用 sync.Pool 引用作为上下文值是否安全?

转载 作者:IT王子 更新时间:2023-10-29 01:47:19 26 4
gpt4 key购买 nike

我有使用 sync.Pool 的结构。

将此引用用作上下文值是否安全?

type User struct {
ID string
}

var userPool = sync.Pool{
New: func() interface{} {
return &User{}
},
}

func getUser() *User {
return userPool.Get().(*User)
}

func recycleUser(user *User) {
userPool.Put(user)
}

用户结构从中间件的池中检索。

func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// get user from pool
user := getUser()
// user must be recycled
ctx := context.WithValue(r.Context(), "user", user)
}
}

并在处理程序中回收。

func getUser(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user").(*User)

// TODO: do something with user

// put user struct back into pool
recycleUser(user)
}

编辑:

我的问题更多是关于上下文如何处理指向我的对象的指针。它会复制吗?在上下文中使用非原始对象是否安全?

最佳答案

需要注意三点:

sync.Pool的使用

您对池的使用符合预期。来自 golang Documentation

A Pool is safe for use by multiple goroutines simultaneously.

检索用户

getUser 使用 func (p *Pool) Get() 接口(interface){} 从池中移除返回的项目,之后你可以做任何你想做的事具有该值。在您的例子中,这是一个 *User。是否关联资源可以安全使用,这取决于您在程序的其余部分中对这些值的使用。

回收用户

在处理程序中调用 recycleUser 有潜在危险,具体取决于您的环境。

可能会出现什么问题?

recycleUser 将您的 *User 返回到池中后,它可以立即被不同的 goroutine 检索和使用。但与此同时,*User 仍然存储在与请求关联的上下文中。因此,这取决于您的中间件的任何功能是否也使用上下文中的 *User 以及它们是否存储 *User 值。或者,如果您稍后在使用 *User 值的 recycleUser 之后添加一些代码。在 recycleUser 调用之后,所有这些用法都可能对错误的用户进行操作,该用户已被一些不同的请求使用。

如何解决这些问题

  1. 编码规范

    • 如果您在中间件函数中检索用户,请不要存储它
    • 如果您在中间件函数中检索用户,请不要在调用链中的下一个处理程序后使用它。
    • 不要在中间件函数中调用recycleUser
    • 在叶处理程序中检索用户(链中的最后一个处理程序,不调用任何进一步的处理程序传播上下文,因此不调用 *User)并使用 defer recycleUser(user) *User 放回池中,并使以后添加的代码在调用 recycleUser(user)< 后不可能使用 *User/
    • 在叶处理程序中,不要在叶处理程序中的某些defer 用法调用的代码中使用*UserrecycleUser .
  2. 通过技术手段确保编码约定。我在这里唯一的想法是将 *User 放在某个结构中,并且只对一个请求使用该结构并将其标记为空,一旦 *User 被放回水池。如果访问空结构,则使该结构的所有访问方法检查是否为空和 panic /日志/其他。在上下文中放置指向该结构的指针。但这可能毫无意义,因为您现在为每个请求分配该结构,而不是 User,这可能是您试图避免的。

一个小评论

您的意思可能是您的中间件函数读起来像:

func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// get user from pool
user := getUser()
// user must be recycled
ctx := context.WithValue(r.Context(), "user", user)
// probably do something more
next(w, r.WithContext(ctx))
}
}

关于http - 使用 sync.Pool 引用作为上下文值是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45891769/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com