英文:
why goroutine block main func in this http server?
问题
我想要使用httprouter在两个端口(8888和8080)上设置一个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("监听8080端口")
// 这里会阻塞
go log.Fatal(http.ListenAndServe(":8080", router))
fmt.Println("监听8888端口")
log.Fatal(http.ListenAndServe(":8888", router))
}
但是它不能正常工作,我的服务器只监听8080端口。如果我做一些更改:
go func() { log.Fatal(http.ListenAndServe(":8080", router)) }()
它可以在8080和8888上正常工作。那么为什么会这样呢?是因为闭包还是其他原因?
英文:
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?
答案1
得分: 9
“函数值和参数在调用的goroutine中按照通常的方式进行评估。” —— Go语言规范,“Go语句”。
你正在为调用log.Fatal创建一个goroutine,但是log.Fatal的参数在主goroutine中先进行评估。而Fatal的参数是http.ListenAndServe的返回值。因此,在ListenAndServe返回之后,新的goroutine才会开始执行。
英文:
> 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.
答案2
得分: 8
由于http.ListenAndServe()是阻塞的,并且在您的场景中有两个实例,所以尝试将其中一个放在一个goroutine中。这个想法是将这两个Web服务器初始化语句的执行分离到单独的goroutine中。
func main() {
router := httprouter.New()
router.GET("/", Index)
go func() {
fmt.Println("监听8080端口")
log.Fatal(http.ListenAndServe(":8080", router))
}()
fmt.Println("监听8888端口")
log.Fatal(http.ListenAndServe(":8888", router))
}
英文:
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))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论