Why is my webserver in golang not handling concurrent requests?

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?


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.


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()
        }
}