Request和ResponseWriter将被覆盖

I experiment a little bit with go http package.

Look at the following code snippet, a very simple http server:

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 
", 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")
}

and I make 20 times request to server:

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)

}

I received the following response:

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

As you can see here, everything is fine. Every request and response have different storage address.

So if I change the http server to:

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 
", self.request, self.response)

}

func (self *controller) send() {
    fmt.Fprintf(self.response, "Request %p and Response %p 
", 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")
}

As you can see here I've add the method get and when counter reach number 7, it will sleep for 4 second.

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

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

}

As output I've got

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

As you can see the address from the last two lines is the same, that means by request 7 the address of request and response will be overwrite, because the response is delay.

My question is, when a request have to process intensive calculation, for example resizing image and during the resizing an other request comes in, the request and response from image resizing process will be overwrite like above. Then the response will go to the last requested client. In my opinion, thats wrong right?

I know that go create for every request a new goroutine.

You are introducing a data race:

router.Handle("/", &controller{})

As you can see there is only one instance of the controller type.

self.request = r
self.response = rw

Here you are modifying your struct. But the ServeHTTP() method will be called from multiple goroutines.

An option would be to create a handler like so

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

If you would run your code with the -race flag, it would warn you about this. See also http://blog.golang.org/race-detector

Another thing: don't name your receiver self. This is not idiomatic. It makes your code unreadable. What is self? Give it an appropriate name.