英文:
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))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论