Do I need mutex read lock when retrieving slice values with context in Go?

huangapple go评论78阅读模式
英文:

Do I need mutex read lock when retrieving slice values with context in Go?

问题

我一直在阅读关于上下文和在中间件中传递值的内容。由于julienschmidt httprouter与http.Handler接口不兼容,我想我可以保存httprouter的Params,它是一个Param切片。

https://godoc.org/github.com/julienschmidt/httprouter#Params

然后将其保存在上下文值中以便以后检索。

Go博客上的文章关于上下文:https://blog.golang.org/context 说:

> Value允许上下文携带请求范围的数据。该数据必须对多个goroutine同时使用是安全的。

我不知道这些数据是否安全。据我了解,切片不是线程安全的,但在这种情况下,多个goroutine如何访问数据?

我有一个处理程序,将http.Handler转换为httprouter.Handle,并保存httprouter.Params,以便我可以在http.HandlerFunc类型的函数中使用这些参数。

type ctxKey string

var paramKey ctxKey = "params"

func paramHandler(h http.Handler) httprouter.Handle {
	return httprouter.Handle(func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		ctx := context.WithValue(r.Context(), paramKey, ps)
		h.ServeHTTP(w, r.WithContext(ctx))
	})
}

var mutex sync.RWMutex

func params(r *http.Request) httprouter.Params {
	// https://blog.golang.org/context
	// "Value allows a Context to carry request-scoped data.
	// That data must be safe for simultaneous use by multiple goroutines."
	mutex.RLock()
	value := r.Context().Value(paramKey)
	mutex.RUnlock()
	if ps, ok := value.(httprouter.Params); ok {
		return ps
	}
	return httprouter.Params{}
}

在paramHandler中,我设置了上下文值,它是一个httprouter.Param的切片,而在params(r *http.Request)函数中,我接收这些参数。

我的问题是,在paramHandler中保存参数切片到上下文时,是否需要写锁,以及在param(*http.Request)函数中检索参数时是否需要读锁?

我计划像这样检索参数:

func getUser(w http.ResponseWriter, r *http.Request) {
	ps := params(r)
	fmt.Println(ps.ByName("id"))
}

这些锁是否必要?

英文:

I have been reading about context and passing values in middlewares. Since the julienschmidt httprouter is not compatible with http.Handler interface I thought I could save the httprouter Params which is a slice of Param

https://godoc.org/github.com/julienschmidt/httprouter#Params

and save this in a context value and retrieve later.

The Go blog article on context: https://blog.golang.org/context says that:

> Value allows a Context to carry request-scoped data. That data must be
> safe for simultaneous use by multiple goroutines.

I don't know if this data is safe. Slices are not thread safe as I understand, but how would multiple go routines access the data in this situation?

I have a handler that converts http.Handler to httprouter.Handle and saves the httprouter.Params so that I can use those params in http.HandlerFunc type functions.

type ctxKey string

var paramKey ctxKey = "params"

func paramHandler(h http.Handler) httprouter.Handle {
	return httprouter.Handle(func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		ctx := context.WithValue(r.Context(), paramKey, ps)
		h.ServeHTTP(w, r.WithContext(ctx))
	})
}

var mutex sync.RWMutex

func params(r *http.Request) httprouter.Params {
	// https://blog.golang.org/context
	// "Value allows a Context to carry request-scoped data.
	// That data must be safe for simultaneous use by multiple goroutines."
	mutex.RLock()
	value := r.Context().Value(paramKey)
	mutex.RUnlock()
	if ps, ok := value.(httprouter.Params); ok {
		return ps
	}
	return httprouter.Params{}
}

In paramHandler I set the context value which is a slice of httprouter.Param, and in params(r *http.Request) function I receive the parameters.

My question is, do I need write locks when saving the slice of params in context in paramHandler, and read locks when retrieving the params from context as I have in the function param(*http.Request)?

I plan on retrieving the params like this:

func getUser(w http.ResponseWriter, r *http.Request) {
	ps := params(r)
	fmt.Println(ps.ByName("id"))
}

Are the locks necessary?

答案1

得分: 0

你担心数据竞争问题。这里有一些关于Go语言博客的有用信息:

数据竞争是并发系统中最常见且最难调试的错误类型之一。当两个goroutine同时访问同一个变量,并且至少有一个访问是写操作时,就会发生数据竞争。

你可以阅读关于竞争检测器的博客文章介绍。

所以,如果你不确定是否存在数据竞争,可以运行竞争检测器。这很简单,只需设置-race标志,Go语言会检查是否存在数据竞争。

当你正常使用上下文时,通常不需要加锁,因为上下文会通过所有调用传递,并且对于每个新的调用,内存中会有另一个地址。

如果你只是从一个变量中读取值,也不需要加锁,因为这样值永远不会改变。

英文:

You are worried about a data race. Here is something helpful on the golang blog:

> Data races are among the most common and hardest to debug types of
> bugs in concurrent systems. A data race occurs when two goroutines
> access the same variable concurrently and at least one of the accesses
> is a write.

The introduction to the race detector blog entry

So if you are not sure you can run the race detector. Because it is not complicated. Just set the flag -race and go will check if there is a data race.

When you use context normally you don't need to lock, because is passed through all the calls and for every new call there will be another address inside the memory.

If you always read from a variable you don't need to lock it, because then the value will never change.

huangapple
  • 本文由 发表于 2017年3月20日 08:07:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/42893937.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定