为什么我的Golang Web服务器不能处理并发请求?

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

Why is my webserver in golang not handling concurrent requests?

问题

这个简单的HTTP服务器包含一个调用time.Sleep()的函数,使得每个请求需要五秒钟的时间。当我尝试在浏览器中快速加载多个标签页时,很明显每个请求都是按顺序排队处理的。我该如何使其能够处理并发请求?

package main

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

func serve(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "Hello, world.")
   time.Sleep(5 * time.Second)
}

func main() {
   http.HandleFunc("/", serve)
   http.ListenAndServe(":1234", nil) 
}

实际上,在写这个问题之后,我刚刚找到了答案,而且它非常微妙。我还是会发布它,因为我在谷歌上找不到答案。你能看出我做错了什么吗?

英文:

This simple HTTP server contains a call to time.Sleep() that makes
each request take five seconds. When I try quickly loading multiple
tabs in a browser, it is obvious that each request
is queued and handled sequentially. How can I make it handle concurrent requests?

package main

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

func serve(w http.ResponseWriter, r *http.Request) {
   fmt.Fprintln(w, "Hello, world.")
   time.Sleep(5 * time.Second)
}

func main() {
   http.HandleFunc("/", serve)
   http.ListenAndServe(":1234", nil) 
}

Actually, I just found the answer to this after writing the question, and it is very subtle. I am posting it anyway, because I couldn't find the answer on Google. Can you see what I am doing wrong?

答案1

得分: 113

你的程序已经可以并发处理请求了。你可以使用ab进行测试,它是随Apache 2一起提供的基准测试工具:

ab -c 500 -n 500 http://localhost:1234/

在我的系统上,这个基准测试总共花费了5043毫秒来处理所有的500个并发请求。只是你的浏览器限制了每个网站的连接数。

顺便说一下,对Go程序进行基准测试并不容易,因为你需要确保你的基准测试工具不是瓶颈,并且能够处理那么多并发连接。因此,使用几台专用的计算机来生成负载是一个好主意。

英文:

Your program already handles the requests concurrently. You can test it with ab, a benchmark tool which is shipped with Apache 2:

ab -c 500 -n 500 http://localhost:1234/

On my system, the benchmark takes a total of 5043ms to serve all 500 concurrent requests. It's just your browser which limits the number of connections per website.

Benchmarking Go programs isn't that easy by the way, because you need to make sure that your benchmark tool isn't the bottleneck and that it is also able to handle that many concurrent connections. Therefore, it's a good idea to use a couple of dedicated computers to generate load.

答案2

得分: 14

从Server.go中,当接受到一个连接时,Serve函数会生成一个go routine。以下是代码片段:

// Serve函数在Listener l上接受传入的连接,为每个连接创建一个新的服务goroutine。
// 服务goroutine读取请求,然后调用srv.Handler来回复请求。
func (srv *Server) Serve(l net.Listener) error {
    for {
        rw, e := l.Accept()
        if e != nil {
......
        c, err := srv.newConn(rw)
        if err != nil {
            continue
        }
        c.setState(c.rwc, StateNew) // 在Serve返回之前
        go c.serve()
    }
}
英文:

From Server.go , the go routine is spawned in the Serve function when a connection is accepted. Below is the snippet, :-

// Serve accepts incoming connections on the Listener l, creating a 
// new service goroutine for each.  The service goroutines read requests and
// then call srv.Handler to reply to them.
func (srv *Server) Serve(l net.Listener) error {
		for {
			rw, e := l.Accept()
  			   if e != nil {
......
			c, err := srv.newConn(rw)
			if err != nil {
				continue
			}
			c.setState(c.rwc, StateNew) // before Serve can return
			go c.serve()
		}
}

答案3

得分: -6

如果您使用xhr请求,请确保xhr实例是一个局部变量。

例如,xhr = new XMLHttpRequest()是一个全局变量。当您使用相同的xhr变量进行并行请求时,您只会收到一个结果。因此,您必须像这样在本地声明xhr var xhr = new XMLHttpRequest()

英文:

If you use xhr request, make sure that xhr instance is a local variable.

For example, xhr = new XMLHttpRequest() is a global variable. When you do parallel request with the same xhr variable you receive only one result. So, you must declare xhr locally like this var xhr = new XMLHttpRequest().

huangapple
  • 本文由 发表于 2012年5月23日 21:23:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/10720867.html
匿名

发表评论

匿名网友

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

确定