为了账号安全,请及时绑定邮箱和手机立即绑定

何时将sync.Mutex与net/http和gorilla/mux一起使用

何时将sync.Mutex与net/http和gorilla/mux一起使用

Go
DIEA 2023-07-31 17:35:57
据我所知, net/http 包使用 goroutine 作为处理程序。我是否有必要锁定地图,sync.Mutex以防止nextId函数中可能出现错误,因为该函数可能会计算地图的旧状态?这是我的示例代码:package mainimport (    "net/http"    "github.com/gorilla/mux"    "io/ioutil"    "fmt")var testData = map[int]string {    1: "foo",    2: "bar",}func main() {    r := mux.NewRouter()    r.HandleFunc("/data", getData).Methods("GET")    r.HandleFunc("/data", addData).Methods("POST")    http.ListenAndServe(":3000", r)}func getData(writer http.ResponseWriter, request *http.Request) {    for k, v := range testData {        fmt.Fprintf(writer, "Key: %d\tValue: %v\n", k, v)    }}func addData(writer http.ResponseWriter, request *http.Request) {    if data, err := ioutil.ReadAll(request.Body); err == nil {        if len(data) == 0 {            writer.WriteHeader(http.StatusBadRequest)            return        }        id := nextId()        testData[id] = string(data)        url := request.URL.String()        writer.Header().Set("Location", fmt.Sprintf("%s", url))        writer.WriteHeader(http.StatusCreated)    } else {        writer.WriteHeader(http.StatusBadRequest)    }}func nextId() int {    id := 1    for k, _ := range testData {        if k >= id {            id = k + 1;        }    }    return id}
查看完整描述

1 回答

?
墨色风雨

TA贡献1853条经验 获得超6个赞

由于标准库的 HTTP 服务器在其自己的 goroutine 上调用处理程序,因此您必须同步访问处理程序外部定义的所有变量(其中访问之一是写入)。每当您使用 stdlib 的 HTTP 服务器时都必须执行此操作。使用标准库的多路复用器还是 Gorilla 的多路复用器并不重要。Goroutine 启动发生在多路复用器外部(在调用多路复用器之前)。


如果不这样做(如您的示例中所示),则会发生数据争用,您可以通过使用以下选项运行它来验证-race:


WARNING: DATA RACE

Write at 0x00c000090c30 by goroutine 21:

  runtime.mapassign_fast64()

      /usr/local/go/src/runtime/map_fast64.go:92 +0x0

  main.addData()

      /home/icza/gows/src/play/play.go:47 +0x191

  net/http.HandlerFunc.ServeHTTP()

      /usr/local/go/src/net/http/server.go:2007 +0x51

  github.com/gorilla/mux.(*Router).ServeHTTP()

      /home/icza/gows/pkg/mod/github.com/gorilla/mux@v1.7.3/mux.go:212 +0x13e

  net/http.serverHandler.ServeHTTP()

      /usr/local/go/src/net/http/server.go:2802 +0xce

  net/http.(*conn).serve()

      /usr/local/go/src/net/http/server.go:1890 +0x837


Previous read at 0x00c000090c30 by goroutine 7:

  runtime.mapiternext()

      /usr/local/go/src/runtime/map.go:851 +0x0

  main.getData()

      /home/icza/gows/src/play/play.go:32 +0x194

  net/http.HandlerFunc.ServeHTTP()

      /usr/local/go/src/net/http/server.go:2007 +0x51

...


查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 106 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信