英文:
Is it always okay to use variables concurrently in Go?
问题
我正在编写一个小型的Web服务器程序,它需要对POST请求中的JSON进行解码。
最初,我考虑的是不要每次请求都初始化一个新的json.Decoder
,而是将其作为一个全局变量,在每次调用时并发地进行解码。
作为Go的新手,这样做可以吗?是否有时候我不应该这样做,因为类可能会因为不是线程安全(我猜应该是"goroutine"安全更好)而出现问题?
英文:
I'm writing a small webserver program, and it does a lot of JSON decoding from POST requests coming in.
Initially I thought that instead of initializing a new json.Decoder
every time a request comes in, I have it as a global variable that gets called on every time and decodes concurrently with goroutines.
As a newcomer to Go, is this okay? Are there times when I shouldn't be doing this and classes will freak out due to not being thread safe (I guess "goroutine" safe would be better)?
答案1
得分: 6
在Go语言中,json.NewDecoder接受一个io.Reader作为输入参数,并返回一个*json.Decoder。因此,由于每个POST请求都有不同的http.Request.Body(实现了io.Reader),所以无法重用相同的Decoder。
正如Paul Hankin所提到的,除非文档明确说明可以并发使用,否则不能同时使用Go对象。
示例:
-
http.Client和http.Transport
客户端和传输器可以安全地被多个goroutine并发使用,并且为了效率应该只创建一次并重复使用。
-
Maps(映射)
经过长时间的讨论,决定了映射的典型用法不需要从多个goroutine安全访问。
如果你询问如何重用JSON解码器以避免代码重复,你可以看看像Tigertonic和Go-Json-Rest这样的框架。
另外,你可以查看ffjson来加速JSON解码。
英文:
In Go, json.NewDecoder takes an io.Reader as an input parameter and returns a *json.Decoder. Hence it is not possible to reuse the same Decoder since we have a different http.Request.Body (which implements io.Reader) for each POST request.
And as mentioned by Paul Hankin, you can't use go objects concurrently unless they're documented to be safe to use concurrently.
Examples :
> 1. http.Client & http.Transport
> Clients and Transports are safe for
> concurrent use by multiple goroutines and for efficiency should only
> be created once and re-used.
> 2. Maps
> After long discussion it was decided that the typical use of maps did not require safe access from multiple goroutines.
If you asked about reusing JSON decoder to avoid the duplication of code you could look at frameworks like Tigertonic and Go-Json-Rest.
On a side note you could look at ffjson to speed up JSON Decoding.
答案2
得分: 2
像约翰和保罗说的那样,这不会按照你的期望工作。
如果你的主要关注是代码重复,你可能需要一个中间件。以下是一个示例,展示了你可以如何实现:
type JSONHandler func(http.ResponseWriter, *http.Request, *json.Decoder)
func JSONMiddleware(handler JSONHandler) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body)
handler(w, req, decoder)
}
}
func MyHandler(w http.ResponseWriter, req *http.Request, decoder *json.Decoder) {
// 在这里放置你的代码,你可以访问到解码器(decoder)
}
func main() {
http.HandleFunc("/myroute", JSONMiddleware(MyHandler))
// ...
}
(在 playground 上查看:https://play.golang.org/p/4ZTaQguNj7)
英文:
Like John and Paul said, this won't do what you expect it to.
If your main concern is code duplication, what you probably want is a middleware. Here is an example of how you could do it
type JSONHandler func(http.ResponseWriter, *http.Request, *json.Decoder)
func JSONMiddleware(handler JSONHandler) http.HandlerFunc{
return func(w http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body)
handler(w, req, decoder)
}
}
func MyHandler(w http.ResponseWriter, req *http.Request, decoder *json.Decoder) {
// Put your code here, you have access to the decoder
}
func main() {
http.HandleFunc("/myroute", JSONMiddleware(MyHandler))
...
}
(on playground: https://play.golang.org/p/4ZTaQguNj7)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论