我的结构使用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)
}
编辑:
我的问题更多的是关于上下文如何处理指向我的对象的指针。它是否复制?在上下文中使用非原始对象是否安全?
答案 0 :(得分:0)
要做三点:
您对游泳池的使用是按预期的。来自golang Documentation
池可以安全地同时使用多个goroutine。
getUser
使用func (p *Pool) Get() interface{}
从池中删除退回的项目,之后您可以随心所欲地做任何事情
有这个价值。在你的情况下,那是一个*User
。是否相关
ressource可以安全使用,取决于你在程序其余部分中对这些值的使用。
根据您的环境,在管理员中调用recycleUser
可能会有危险。
可能出现什么问题?
recycleUser
将*User
返回池后,可以立即检索并使用其他goroutine。但与此同时,*User
仍存储在与请求相关联的上下文中。因此,取决于中间件的任何功能是否也使用上下文中的*User
,并且它们存储*User
值。或者,如果您稍后在使用recycleUser
值的*User
之后添加一些代码。在recycleUser
调用之后,所有这些用法可能都在错误的用户上运行,这已被某些不同的请求使用。
编码惯例
recycleUser
*User
)并使用defer recycleUser(user)
来放回{池中的{1}}使得以后添加的代码无法在调用*User
后使用*User
。recycleUser(user)
,该代码由叶子处理程序中的某些*User
用法调用,而不是defer
。通过技术手段确保编码惯例。我唯一的想法是将recycleUser
置于某个结构中,并仅将该结构用于一个请求,并将*User
放回池中后将其标记为空。如果访问空结构,则使该结构的所有访问方法检查空白和panic / log / whatever。在上下文中放置一个指向该结构的指针。但这可能毫无意义,因为您现在为每个请求分配该结构,而不是*User
,这可能是您试图避免的。
您可能意味着您的中间件功能如下:
User