最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

如何以编程方式证明此代码具有竞争条件?

SEO心得admin100浏览0评论
本文介绍了如何以编程方式证明此代码具有竞争条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我被告知此代码在设计上具有竞争条件,尽管我尝试了一下,但我无法证明它确实存在.

I'm told this code has a race condition by design, though try as I may, I'm unable to prove it does.

func (h *handler) loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h.Log = log.WithFields(log.Fields{ "method": r.Method, "requestURI": r.RequestURI, }) next.ServeHTTP(w, r) }) }

我尝试了go build -race,然后运行二进制文件:PORT=3000 ./main&加载hey -n 10000 -c 200 localhost:3000之类的创建者.

I tried go build -race, then running the binary: PORT=3000 ./main & load creators like hey -n 10000 -c 200 localhost:3000.

此处的其余代码: raw .githubusercontent/kaihendry/context-youtube/master/5/main.go

type handler struct{ Log *log.Entry } func New() (h *handler) { return &handler{Log: log.WithFields(log.Fields{"test": "FAIL"})} } func (h *handler) index(w http.ResponseWriter, r *http.Request) { h.Log.Info("index") fmt.Fprintf(w, "hello") } func (h *handler) about(w http.ResponseWriter, r *http.Request) { h.Log.Info("about") fmt.Fprintf(w, "about") } func main() { h := New() app := mux.NewRouter() app.HandleFunc("/", h.index) app.HandleFunc("/about", h.about) app.Use(h.loggingMiddleware) if err := http.ListenAndServe(":"+os.Getenv("PORT"), app); err != nil { log.WithError(err).Fatal("error listening") } }

如果我不能证明它具有竞赛条件,我可以假定设置h.Log是安全的吗?

If I can't prove it has a race condition, can I assume setting h.Log is safe?

推荐答案

有一种编程方式,为此您必须做两件事:

There is a programmatic way, for which you have to do 2 things:

  • 再现民主状况
  • 并在启动go工具时使用-race选项
  • reproduce the racy condition
  • and use the -race option when launching the go tool

最好是为它编写一个单元测试,因此该测试也是可重复的,并且可以在每次构建/部署时自动运行/检查.

Best is if you write a unit test for it, so the test is also reproducible, and run / checked automatically on each build / deploy.

好,那么如何重现呢?

只需编写一个测试,该测试将有意地在没有同步的情况下启动两个goroutine,一个调用index处理程序,一个调用about处理程序,这就是触发竞赛检测器的原因.

Simply write a test which launches 2 goroutines, one which calls the index handler, and one which calls the about handler, deliberately without synchronization, this is what triggers the race detector.

使用 net/http/httptest 包可以轻松测试处理程序. httptest.NewServer() 会为您准备就绪的服务器,并与处理程序武装"在一起你传递给它.

Use the net/http/httptest package to easily test handlers. httptest.NewServer() hands you a ready server, "armed" with the handler you pass to it.

这是一个简单的测试示例,它将触发竞争条件.将其放在main.go文件旁边的名为main_test.go的文件中:

Here's a simple test example that will trigger the race condition. Put it in a file named main_test.go, next to your main.go file:

package main import ( "fmt" "net/http" "net/http/httptest" "sync" "testing" "github/gorilla/mux" ) func TestRace(t *testing.T) { h := New() app := mux.NewRouter() app.HandleFunc("/", h.index) app.HandleFunc("/about", h.about) app.Use(h.loggingMiddleware) server := httptest.NewServer(app) defer server.Close() wg := &sync.WaitGroup{} for _, path := range []string{"/", "/about"} { path := path wg.Add(1) go func() { defer wg.Done() req, err := http.NewRequest(http.MethodGet, server.URL+path, nil) fmt.Println(server.URL + path) if err != nil { panic(err) } res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() }() } wg.Wait() }

您必须使用它运行

go test -race

示例输出为:

127.0.0.1:33007/ 127.0.0.1:33007/about ================== WARNING: DATA RACE Write at 0x00c000098030 by goroutine 17: play.(*handler).loggingMiddleware.func1() /home/icza/tmp/gows/src/play/main.go:16 +0x1ce net/http.HandlerFunc.ServeHTTP() /usr/local/go/src/net/http/server.go:1964 +0x51 github/gorilla/mux.(*Router).ServeHTTP() /home/icza/tmp/gows/src/github/gorilla/mux/mux.go:212 +0x12e net/http.serverHandler.ServeHTTP() /usr/local/go/src/net/http/server.go:2741 +0xc4 net/http.(*conn).serve() /usr/local/go/src/net/http/server.go:1847 +0x80a Previous write at 0x00c000098030 by goroutine 16: play.(*handler).loggingMiddleware.func1() /home/icza/tmp/gows/src/play/main.go:16 +0x1ce net/http.HandlerFunc.ServeHTTP() /usr/local/go/src/net/http/server.go:1964 +0x51 github/gorilla/mux.(*Router).ServeHTTP() /home/icza/tmp/gows/src/github/gorilla/mux/mux.go:212 +0x12e net/http.serverHandler.ServeHTTP() /usr/local/go/src/net/http/server.go:2741 +0xc4 net/http.(*conn).serve() /usr/local/go/src/net/http/server.go:1847 +0x80a Goroutine 17 (running) created at: net/http.(*Server).Serve() /usr/local/go/src/net/http/server.go:2851 +0x4c5 net/http/httptest.(*Server).goServe.func1() /usr/local/go/src/net/http/httptest/server.go:280 +0xac Goroutine 16 (running) created at: net/http.(*Server).Serve() /usr/local/go/src/net/http/server.go:2851 +0x4c5 net/http/httptest.(*Server).goServe.func1() /usr/local/go/src/net/http/httptest/server.go:280 +0xac ================== 2019/01/06 14:58:50 info index method=GET requestURI=/ 2019/01/06 14:58:50 info about method=GET requestURI=/about --- FAIL: TestRace (0.00s) testing.go:771: race detected during execution of test FAIL exit status 1 FAIL play 0.011s

测试失败,表明存在数据争用.

The test fails, showing that there are data races.

注释:

与sync.WaitGroup的同步是等待2个启动的goroutine,而不是同步对处理程序记录器的访问(这会导致数据争用).这样一来,如果您解决了数据争用问题,则测试将正常运行并结束(等待2个已启动的test-goroutines完成).

The synchronization with the sync.WaitGroup is to wait for the 2 launched goroutines, it is not to synchronize access to the handler's logger (which causes the data race). This is so if you fix the data race, the test will run and end properly (waiting for the 2 launched test-goroutines to complete).

发布评论

评论列表(0)

  1. 暂无评论