dongliao3742 2014-11-26 16:10
浏览 36
已采纳

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.

  • 写回答

1条回答 默认 最新

  • dongxian7489 2014-11-26 16:19
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么