Request和ResponseWriter将被覆盖

zer*_*ing 1 go

我试试了一下http包.

查看以下代码片段,一个非常简单的http服务器:

package main

import (
    "fmt"
    "github.com/codegangsta/negroni"
    "github.com/gorilla/mux"
    "net/http"
    //"time"
)

type controller struct {
    request  *http.Request
    response http.ResponseWriter
}

func (self *controller) send() {
    fmt.Fprintf(self.response, "Request %p and Response %p \n", self.request, self.response)
}

func (self *controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
    fmt.Println("Start controller")
    self.request = r
    self.response = rw

    self.send()
}

func main() {

    router := mux.NewRouter()
    router.Handle("/", &controller{})

    n := negroni.Classic()
    n.UseHandler(router)

    n.Run(":3000")
}
Run Code Online (Sandbox Code Playgroud)

我向服务器发出20次请求:

package main

import (
    "fmt"
    "io"
    "net/http"
    "runtime"
    "time"
)

func main() {

    buffer := make([]byte, 100)
    runtime.GOMAXPROCS(runtime.NumCPU())

    for i := 0; i < 20; i++ {
        go func(z int) {
            //fmt.Println("Request goroutine 1 ", z)
            resp, err := http.Get("http://127.0.0.1:3000")
            if err != nil {
                fmt.Println(err)
            }

            io.ReadFull(resp.Body, buffer)
            fmt.Println(string(buffer))
        }(i)
    }

    time.Sleep(time.Second * 5)

}
Run Code Online (Sandbox Code Playgroud)

我收到了以下回复:

Request 0xc0820201a0 and Response 0xc082007100

Request 0xc082021380 and Response 0xc0820072c0

Request 0xc0820204e0 and Response 0xc082007740

Request 0xc082020dd0 and Response 0xc0820071c0

Request 0xc082020d00 and Response 0xc082007240

Request 0xc082021450 and Response 0xc082007400

Request 0xc082020f70 and Response 0xc082007500

Request 0xc082021110 and Response 0xc082007480

Request 0xc0820212b0 and Response 0xc082007540

Request 0xc082020b60 and Response 0xc0820075c0

Request 0xc082020750 and Response 0xc082007640

Request 0xc082020270 and Response 0xc0820076c0

Request 0xc082020c30 and Response 0xc082007840

Request 0xc082020820 and Response 0xc0820078c0

Request 0xc082020ea0 and Response 0xc082007940

Request 0xc0820211e0 and Response 0xc0820079c0

Request 0xc082021520 and Response 0xc082007a40

Request 0xc0820209c0 and Response 0xc082007ac0

Request 0xc082021040 and Response 0xc082007380

Request 0xc082020a90 and Response 0xc0820077c0
Run Code Online (Sandbox Code Playgroud)

正如你在这里看到的,一切都很好.每个请求和响应都有不同的存储地址.

所以,如果我将http服务器更改为:

package main

import (
    "fmt"
    "github.com/codegangsta/negroni"
    "github.com/gorilla/mux"
    "net/http"
    "time"
)

type controller struct {
    request  *http.Request
    response http.ResponseWriter
    counter  int
}


func (self *controller) get() {
    self.counter++
    if self.counter == 7 {
        time.Sleep(time.Second * 4)
    }

    fmt.Printf("Request %p and Response %p \n", self.request, self.response)

}

func (self *controller) send() {
    fmt.Fprintf(self.response, "Request %p and Response %p \n", self.request, self.response)
}

func (self *controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
    fmt.Println("Start controller")
    self.request = r
    self.response = rw

    self.get()
    self.send()
}

func main() {

    router := mux.NewRouter()
    router.Handle("/", &controller{})

    n := negroni.Classic()
    n.UseHandler(router)

    n.Run(":3000")
}
Run Code Online (Sandbox Code Playgroud)

正如你在这里看到的那样,我添加了方法get,当计数器达到7时,它会睡4秒钟.

func (self *controller) get() {
    self.counter++
    if self.counter == 7 {
        time.Sleep(time.Second * 4)
    }

    fmt.Printf("Request %p and Response %p \n", self.request, self.response)

}
Run Code Online (Sandbox Code Playgroud)

作为输出我有

Request 0xc082021040 and Response 0xc082007100

Request 0xc0820209c0 and Response 0xc082007240

Request 0xc0820211e0 and Response 0xc082007380

Request 0xc082020270 and Response 0xc082007500

Request 0xc082020d00 and Response 0xc082007640

Request 0xc082020f70 and Response 0xc082007740

Request 0xc082020680 and Response 0xc082007840

Request 0xc082020820 and Response 0xc082007940

Request 0xc082020b60 and Response 0xc082007a40

Request 0xc082021380 and Response 0xc0820071c0

Request 0xc082021110 and Response 0xc0820072c0

Request 0xc0820208f0 and Response 0xc082007400

Request 0xc082020a90 and Response 0xc082007540

Request 0xc082020340 and Response 0xc0820076c0

Request 0xc082020750 and Response 0xc0820075c0

Request 0xc082020dd0 and Response 0xc0820077c0

Request 0xc0820212b0 and Response 0xc0820078c0

Request 0xc0820201a0 and Response 0xc0820079c0

Request 0xc082020ea0 and Response 0xc082007ac0

Request 0xc082020ea0 and Response 0xc082007ac0
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,最后两行的地址是相同的,这意味着请求7将覆盖请求和响应的地址,因为响应是延迟.

我的问题是,当请求必须处理密集计算时,例如调整图像大小,并且在调整大小期间,其他请求进入,图像大小调整过程的请求和响应将被覆盖,如上所述.然后响应将转到最后请求的客户端.在我看来,这是错的吧?

我知道为每个请求创建一个新的goroutine.

seo*_*ong 5

您正在介绍数据竞赛:

router.Handle("/", &controller{})
Run Code Online (Sandbox Code Playgroud)

如您所见,该controller类型只有一个实例.

self.request = r
self.response = rw
Run Code Online (Sandbox Code Playgroud)

在这里,您正在修改结构.但是这个ServeHTTP()方法将从多个goroutine调用.

一个选项是创建一个像这样的处理程序

router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    c := &controller{request: r, response: w)
    c.send()
    ...
})
Run Code Online (Sandbox Code Playgroud)

如果您使用该-race标志运行您的代码,它会警告您这一点.另见http://blog.golang.org/race-detector

另一件事:不要命名你的接收器self.这不是惯用语.它使您的代码不可读.什么是self?给它一个合适的名字.