Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

concurrent http request gives no response

Tags:

concurrency

go

I am playing around with Go a bit and I've a problem that I am unable to solve.

The following code is the least possible code that reproduces my problem. The goal of the original code is to delegate http request to goroutines. Each goroutine does a bit of heavy image calculations and is supposed to respond.

package main

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

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

func handle(w http.ResponseWriter, r *http.Request) {

    // the idea is to be able to handle several requests
    // in parallel

    // the "go" is problematic
    go delegate(w)
}

func delegate(w http.ResponseWriter) {

    // do some heavy calculations first

    // present the result (in the original code, the image)
    fmt.Fprint(w, "hello")
}

In the case of a go delegate(w) I get no response, without the go it works out nicely.

Can anyone explain what's going on? Thanks a lot!

like image 945
ffel Avatar asked Oct 22 '12 20:10

ffel


2 Answers

ListenAndServe already launches goroutines to call your handler function, so you shouldn't do it yourself.

Here's the code of the relevant functions from the package source :

1089    func ListenAndServe(addr string, handler Handler) error {
1090        server := &Server{Addr: addr, Handler: handler}
1091        return server.ListenAndServe()
1092    }


1010    func (srv *Server) ListenAndServe() error {
1011        addr := srv.Addr
1012        if addr == "" {
1013            addr = ":http"
1014        }
1015        l, e := net.Listen("tcp", addr)
1016        if e != nil {
1017            return e
1018        }
1019        return srv.Serve(l)
1020    }


1025    func (srv *Server) Serve(l net.Listener) error {
1026        defer l.Close()
1027        var tempDelay time.Duration // how long to sleep on accept failure
1028        for {

1057            go c.serve()
1058        }
1059        panic("not reached")
1060    }


579 // Serve a new connection.
580 func (c *conn) serve() {
581     defer func() {
582         err := recover()

669         handler.ServeHTTP(w, w.req)

So your code should simply be

func handle(w http.ResponseWriter, r *http.Request) {
    // the idea is to be able to handle several requests
    // in parallel
    // do some heavy calculations first

    // present the result (in the original code, the image)
    fmt.Fprint(w, "hello")
}
like image 189
Denys Séguret Avatar answered Nov 02 '22 08:11

Denys Séguret


The handler is already called from an "outer" goroutine (a per request one). The handler must do everything what has to be done, e.g. writing a full response, before it returns. You're returning "prematurely" b/c of a superfluous go statement. Please try simply to put the body of "delegate" in 'handle' and check if that improves something ;-)

like image 32
zzzz Avatar answered Nov 02 '22 06:11

zzzz