首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当在goroutine中添加处理程序时,如何防止数据竞争?

当在goroutine中添加处理程序时,如何防止数据竞争?
EN

Stack Overflow用户
提问于 2018-04-30 13:44:56
回答 1查看 562关注 0票数 3

在我用golang编写的HTTP应用程序中,我有几条路由依赖于第三方服务(和端端代码)来完成一些工作,然后才能真正注册路由。这可能失败或需要重新尝试,但我仍然希望应用程序响应其他请求,而这是进程可能正在进行的。

这意味着我在http.DefaultServeMux上注册处理程序,这些处理程序是我从main函数中生成的。这如预期的那样工作,但我现在会发现我的测试抱怨数据竞争。

复制的最小案例如下所示:

代码语言:javascript
复制
package main

import (
    "log"
    "net/http"
)

func main() {
    go func() {
        http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
            w.Write([]byte("hello"))
        })
    }()
    srv := http.Server{
        Addr: ":3000",
    }
    log.Fatal(srv.ListenAndServe())
}

通过这样的测试:

代码语言:javascript
复制
package main

import (
    "io/ioutil"
    "net/http"
    "os"
    "testing"
    "time"
)

func TestMain(m *testing.M) {
    go main()
    time.Sleep(time.Second)
    os.Exit(m.Run())
}

func TestHello(t *testing.T) {
    t.Run("default", func(t *testing.T) {
        res, err := http.DefaultClient.Get("http://0.0.0.0:3000/hello")
        if err != nil {
            t.Fatalf("Calling /hello returned %v", err)
        }
        if res.StatusCode != http.StatusOK {
            b, _ := ioutil.ReadAll(res.Body)
            defer res.Body.Close()
            t.Errorf("Expected /hello to return 200 response, got %v with body %v", res.StatusCode, string(b))
        }
    })
}

将向我展示以下输出:

代码语言:javascript
复制
==================
WARNING: DATA RACE
Read at 0x000000a337d8 by goroutine 14:
  net/http.(*ServeMux).shouldRedirect()
      /usr/local/go/src/net/http/server.go:2239 +0x162
  net/http.(*ServeMux).redirectToPathSlash()
      /usr/local/go/src/net/http/server.go:2224 +0x64
  net/http.(*ServeMux).Handler()
      /usr/local/go/src/net/http/server.go:2293 +0x184
  net/http.(*ServeMux).ServeHTTP()
      /usr/local/go/src/net/http/server.go:2336 +0x6d
  net/http.serverHandler.ServeHTTP()
      /usr/local/go/src/net/http/server.go:2694 +0xb9
  net/http.(*conn).serve()
      /usr/local/go/src/net/http/server.go:1830 +0x7dc

Previous write at 0x000000a337d8 by goroutine 8:
  net/http.(*ServeMux).Handle()
      /usr/local/go/src/net/http/server.go:2357 +0x216
  net/http.(*ServeMux).HandleFunc()
      /usr/local/go/src/net/http/server.go:2368 +0x62
  net/http.HandleFunc()
      /usr/local/go/src/net/http/server.go:2380 +0x68
  github.com/m90/test.main.func1()
      /home/frederik/projects/go/src/github.com/m90/test/main.go:10 +0x4f

Goroutine 14 (running) created at:
  net/http.(*Server).Serve()
      /usr/local/go/src/net/http/server.go:2795 +0x364
  net/http.(*Server).ListenAndServe()
      /usr/local/go/src/net/http/server.go:2711 +0xc4
  github.com/m90/test.main()
      /home/frederik/projects/go/src/github.com/m90/test/main.go:17 +0xb6

Goroutine 8 (finished) created at:
  github.com/m90/test.main()
      /home/frederik/projects/go/src/github.com/m90/test/main.go:9 +0x46
==================

据我所理解,在堆栈跟踪中读取包的代码http net/http.(*ServeMux).Handler()并不会锁定保护处理程序映射的互斥锁,因为它希望这是由net/http.(*ServeMux).handler()完成的,而在我的场景中,net/http.(*ServeMux).handler()不会被调用。

我是不是做了不该做的事?这是标准库的问题吗?我是不是做错了什么事,我把处理人员的方式,在戈鲁蒂?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-30 14:53:42

这似乎是包http本身的一个问题,即解决了通过这个拉请求

从2018年4月起,修补程序不包括在go1.10.1中,但它应该随go1.11一起发布

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50101853

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档