解决模拟流的基准函数中的数据竞争问题

时间:2017-08-25 13:08:12

标签: go

我正在尝试编写一个基本上将流式CSV基准测试到HTTP端点的功能。

为此,我想生成数据并发布该数据。

然而,go的数据竞争检测器表示存在数据竞争,并且基准测试的结束速度比我认为合理的速度快,所以我猜错了HTTP请求。

我应该如何构建我的测试代码以避免这种情况?

是否有办法等待HTTP客户端调用处理完毕?

func BenchmarkStream(b *testing.B) {
    header := "header\n"
    buf := bytes.NewBufferString(header)

    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        for i := 0; i < b.N; i++ {
            buf.WriteString(fmt.Sprintf("%d\n", i+1))
        }
        wg.Done()
    }()                 <-- this line is mentioned in the data race detector

    w := httptest.NewRecorder()
    r, _ := http.NewRequest("POST", "/", buf)
    h := &MyHandler{}
    h.ServeHTTP(w, r)  

    wg.Wait()

    if w.Code != 200 {
        b.Errorf("test failed")
    }
}
编辑:@Grzegorz之前的评论让我质疑我的方法开始,我用io.Pipe重构了它:

func BenchmarkStream(b *testing.B) {
    pr, pw := io.Pipe()
    go func() {
        pw.Write([]byte("header\n"))

        for i := 0; i < b.N; i++ {
            pw.Write([]byte(fmt.Sprintf("%d\n", i+1)))
        }
    }()

    w := httptest.NewRecorder()
    r, _ := http.NewRequest("POST", "/", pr)
    h := &MyHandler{}
    h.ServeHTTP(w, r)  

    if w.Code != 200 {
        b.Errorf("test failed")
    }
}

2 个答案:

答案 0 :(得分:1)

您正在两个goroutines之间共享buf

答案 1 :(得分:1)

如果您只调用一次处理程序,那么您将无法获得有用的基准测试结果。构建一次请求体,然后一遍又一遍地调用处理程序。

buf := &bytes.Buffer{}
buf.WriteString("header\n")
buf.WriteString(strings.Repeat("1\n", 1000)
body := buf.Bytes()

b.ResetTimer()

for i := 0; i < b.N; i++ {
    w := httptest.NewRecorder()
    r, err := http.NewRequest("POST", "/", bytes.NewReader(body))
    if err != nil {
        b.Fatal(err)
    }

    h := &MyHandler{}
    h.ServeHTTP(w, r)  

    if w.Code != 200 {
        b.Errorf("test failed")
    }
}