LeoTao
LeoTao

Reputation: 343

why goroutine block main func in this http server?

I want to setup a http server with httprouter listening on two ports 8888 and 8080 just like the code below.

package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "log"
    "net/http"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)

    fmt.Println("listen on 8080")
    // this is where blocked
    go log.Fatal(http.ListenAndServe(":8080", router))
    fmt.Println("listen on 8888")
    log.Fatal(http.ListenAndServe(":8888", router))
}

But it doesn't work properly,my server only listen on 8080.If I make some change:

go func() { log.Fatal(http.ListenAndServe(":8080", router)) }()

It works finely both on 8080 and 8888.So why? It's about closure or something else?

Upvotes: 4

Views: 4373

Answers (2)

novalagung
novalagung

Reputation: 11502

Since http.ListenAndServe() is blocking, and in your scenario, there are two of them, then try to put one of them in a goroutine. The idea is to separate the execution of those two web server initialization statements into separate goroutine.

func main() {
    router := httprouter.New()
    router.GET("/", Index)

    go func() {
        fmt.Println("listen on 8080")
        log.Fatal(http.ListenAndServe(":8080", router))
    }()

    fmt.Println("listen on 8888")
    log.Fatal(http.ListenAndServe(":8888", router))
}

Upvotes: 8

hobbs
hobbs

Reputation: 239781

The function value and parameters are evaluated as usual in the calling goroutine

Go language spec, "Go statements".

You're creating a goroutine for the call to log.Fatal, but the arguments to log.Fatal are evaluated beforehand, in the main goroutine. And Fatal's argument is the return value of http.ListenAndServe. So the new goroutine doesn't start until after ListenAndServe returns.

Upvotes: 9

Related Questions