Go `net/http` 在高并发下的一些困惑

Some confusion of Go `net/http` under high concurrency

高并发下有些混乱

我用wrk测试Gin,有一些不确定性。 Gin 似乎并发不安全。

  package main

  import (
    "fmt"
    "sync/atomic"

    "github.com/gin-gonic/gin"
  )

  var count int64 = 0

  func Test(c *gin.Context) {
    atomic.AddInt64(&count, 1)
    fmt.Println(count)
    c.String(200, "success")
  }

  func main() {
    gin.SetMode(gin.DebugMode)
    router := gin.New()
    router.GET("test", Test)
    router.Run(":8080")
  }

测试shell代码

  wrk -t50 -c50 -d 1s http://localhost:8080/test

Gin输出重复数据

========更新========

即使这样打印代码。

  countCopy := count
  go func() {
    fmt.Println(countCopy)
  }()

我也用ab测试了一下,同样的问题

========更新========

与net/http相同,仍然有重复数据。

  package main

  import (
    "fmt"
    "net/http"
    "sync/atomic"
  )

  var count int64 = 0

  func Test(w http.ResponseWriter, req *http.Request) {
    atomic.AddInt64(&count, 1)
    fmt.Println(count)
    w.Write([]byte("success"))
  }

  func main() {
    http.HandleFunc("/test", Test)
    http.ListenAndServe(":8080", nil)

  }

我尝试使用日志包,它对并发 goroutines 是安全的。一样。

log.Println(countCopy)

您必须使用 atomic.AddInt64(&count, 1) 的返回值,因为 count 可能会在您有机会打印之前更改:

func Test(c *gin.Context) {
    current := atomic.AddInt64(&count, 1)
    fmt.Println(current)
    c.String(200, "success")
}