简体   繁体   English

为什么 goroutine 在这个 http 服务器中阻塞了 main func?

[英]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.我想设置一个带有 httprouter 监听两个端口88888080的 http 服务器,就像下面的代码一样。

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:但它不能正常工作,我的服务器只监听8080 。如果我做一些改变:

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

It works finely both on 8080 and 8888 .So why?它在80808888上都能很好地工作。为什么? It's about closure or something else?closure还是别的什么?

The function value and parameters are evaluated as usual in the calling goroutine函数值和参数在调用 goroutine 中照常评估

Go language spec, "Go statements" . Go 语言规范,“Go 语句”

You're creating a goroutine for the call to log.Fatal , but the arguments to log.Fatal are evaluated beforehand, in the main goroutine.您正在创建呼叫到的goroutine log.Fatal ,但参数log.Fatal预先评估,在主够程。 And Fatal 's argument is the return value of http.ListenAndServe . Fatal的参数是http.ListenAndServe的返回值。 So the new goroutine doesn't start until after ListenAndServe returns.所以新的 goroutine 直到ListenAndServe返回ListenAndServe启动。

Since http.ListenAndServe() is blocking, and in your scenario, there are two of them, then try to put one of them in a goroutine.由于http.ListenAndServe()是阻塞的,并且在您的场景中,有两个,然后尝试将其中一个放在 goroutine 中。 The idea is to separate the execution of those two web server initialization statements into separate goroutine.这个想法是将这两个 Web 服务器初始化语句的执行分开到单独的 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))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM