为什么这个Go HTTP服务器在Chrome 47中没有为每个请求生成一个goroutine?

huangapple go评论90阅读模式
英文:

Why isn't this go HTTP server spawning a goroutine per request in Chrome 47?

问题

之前标题是:“如何为每个HTTP请求生成goroutine?”下面的代码是一个简单的HTTP服务器,它将路径回显给请求者。我使用它来测试net/http包的ListenAndServe方法是否默认触发一个goroutine来处理每个请求;我发现它并不是这样。如果我同时发出三个请求,第一个请求需要10秒才能返回,第二个请求需要20秒(在第一个请求返回后的10秒),第三个请求需要30秒。

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
  time.Sleep(10000 * time.Millisecond)
  fmt.Fprint(w, r.URL.Path)
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}

基本上,我希望主goroutine监听HTTP连接,然后将请求和响应的读取传递给在另一个goroutine中生成的处理程序。

有人可以指导我如何实现这个目标吗?最好使用Go语言的net/http包。

更新 12/21/15 08:46 AM MST

我使用我的Web浏览器(Chrome 47)进行了与您完全相同的测试,即在localhost:8080的根目录下发出五个请求,结果大致如下:

  • 第一个请求:10秒
  • 第二个请求:20秒
  • 第三个请求:30秒
  • 第四个请求:36秒
  • 第五个请求:38秒

所以,希望那些本来会对我的问题进行负面评价的人能够理解我的困惑以及我为什么会做出这样的假设。我不知道为什么在第四个和第五个请求上得到了这样的结果。

我使用curl运行了相同的测试,并得到了与@tomasz相同的结果。

我使用的是go1.2.1版本。

更新 12/21/15 02:08 PM MST

根据@tomasz的建议,我将这个问题的标题从“如何为每个HTTP请求生成goroutine”改为“为什么这个Go HTTP服务器在Chrome 47中没有为每个请求生成goroutine?”

英文:

Previously titled: How to spawn goroutine per HTTP request?

The code below is a simple HTTP server that echos the path back to the requester. I used it to test if the ListenAndServe method of the net/http package by default fires a goroutine to handle each request; which I discovered it doesn't. If I make three requests at the same time, the first takes 10 seconds to return, the second 20 (10 seconds after the first returns), and the third 30 seconds.

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
  time.Sleep(10000 * time.Millisecond)
  fmt.Fprint(w, r.URL.Path)
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}

Basically what I want is the main goroutine to listen for an HTTP connection, then pass the reading of the request and the response to a handler spawned in another goroutine.

Could someone point me in the right direction for accomplishing this? Preferably using the net/http package in go.

UPDATE 12/21/15 08:46 AM MST

I conducted the same exact test you did using my web browser (chrome 47), five requests at the root of localhost:8080, and the results were roughly:

1st: 10 seconds
2nd: 20 seconds
3rd: 30 seconds
4th: 36 seconds     
5th: 38 seconds

So, hopefully, the folks who would otherwise down-vote my question would understand my confusion and why I made the assumption I did. I have no idea why I got the results I did on the 4th and 5th request.

I ran the same test using curl and had the same results as @tomasz.

I'm using go1.2.1.

UPDATE 12/21/15 02:08 PM MST

Per @tomasz's suggestion below, I retitled this question from "How to spawn goroutine per HTTP request" to "Why isn't this go HTTP server spawning a goroutine per request in Chrome 47?"

答案1

得分: 30

一切都很好,你的处理程序在每个请求中都在单独的例程中运行。查看http.Server.Serve方法的源代码。在接受循环的最后一行是:

go c.serve()

问题可能出在你的测试上。如果你通过浏览器的多个标签页来检查行为,匹配的URL请求可能会被排队而不是同时运行它们(也就是说,你的客户端没有使用"例程",而是服务器)。

尝试使用两个不同的浏览器,或者只使用命令行和curl来并行测试请求。例如(借助bash的一些帮助):

$ for i in {1..5}; do time curl localhost:8080 &; done
# 忽略一些混乱之后...
curl localhost:8080  0.00s 用户 0.00s 系统 0% CPU 10.013 总计
curl localhost:8080  0.00s 用户 0.00s 系统 0% CPU 10.014 总计
curl localhost:8080  0.00s 用户 0.00s 系统 0% CPU 10.012 总计
curl localhost:8080  0.00s 用户 0.00s 系统 0% CPU 10.019 总计

你的服务器完美运行。

更新

我可以确认这种行为在Chrome 47上存在,但我还注意到你可以打开多个标签页,比如http://localhost:8080/test1http://localhost:8080/test2等等,你将会得到预期的结果。这表明Chrome确实对匹配的URL有一些排队机制。

英文:

All is good, your handler is run in a separate routine for each request. Take a look at the source code of http.Server.Serve method. The last line in accepting loop says:

go c.serve()

The problem is probably with your testing. If you check the behaviour through the multiple tabs in browser the requests for matching URLs are probably queued instead of running them simultaneously (i.e. your client is not using "routines", not the server).

Try two different browsers or just use command line and, say, curl to test requests in parallel. For example (with some help from bash):

$ for i in {1..5}; do time curl localhost:8080 &; done
# after ignoring some mess...
curl localhost:8080  0.00s user 0.00s system 0% cpu 10.013 total
curl localhost:8080  0.00s user 0.00s system 0% cpu 10.014 total
curl localhost:8080  0.00s user 0.00s system 0% cpu 10.012 total
curl localhost:8080  0.00s user 0.00s system 0% cpu 10.019 total

You server works like a charm.

Update

I can confirm this behaviour on Chrome 47, but also noticed you can open multiple tabs with, say, http://localhost:8080/test1, http://localhost:8080/test2 etc. and you will get expected results. That indicates there's indeed some queuing mechanism in Chrome for matching URLs.

huangapple
  • 本文由 发表于 2015年12月21日 05:46:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/34386232.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定