我对Go的例程并不是很熟悉,但是因为我正在使用net/http
的路由器,所以我看到ListenAndServe()
被一个例行程序包裹了几次。
服务器需要能够同时处理多个请求以提高效率。那么为什么要使用例程作为“轻量级线程”呢? 并发性是否具有任何优势?
以下是OpenShift的示例
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello OpenShift!")
}
func main() {
http.HandleFunc("/", helloHandler)
go func() {
fmt.Println("serving on 8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}()
go func() {
fmt.Println("serving on 8888")
err := http.ListenAndServe(":8888", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}()
select {}
}
答案 0 :(得分:11)
http.ListenAndServe
是一个阻止通话。如果你想做一个更多的工作(比如进行第二次http.ListenAndServe
调用),你需要把它移到一个单独的goroutine上。这就是他们在这里所做的一切。
他们最后使用select{}
来阻止主goroutine,因为他们对http.ListenAndServe
的所有调用都在其他goroutine上。如果他们没有调用select{}
,程序将会终止,因为main()
会返回。
他们可以通过删除select{}
并删除最后一个代码块周围的go func()
包装器来实现相同的功能。但我怀疑他们是这样做的,所以所有代码都是一致的。
但这与表现无关。
在评论中,您提供了一些类似的其他示例。在first example:
func main() {
http.HandleFunc("/", responsehandler.Handler)
go func() {
http.ListenAndServe(":8888", nil)
}()
fileservice.NewWatcher()
}
这会调用http.ListenAndServe
,然后调用fileservice.NewWatcher()
(阻止)。如果他们没有将调用包裹在goroutine中,则fileservice.NewWatcher()
永远不会被调用。
func init() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
}
这将打开调试分析器Web服务器。同样,它是一个goroutine,因此调用init
会立即返回而不是阻塞。这种特殊情况允许呼叫者只是import _ "profiling"
和"神奇地"获取调试分析器Web服务器。
答案 1 :(得分:1)
除了“在后台运行”之外,它没有任何特殊的好处。
答案 2 :(得分:0)
我认为你不需要一个go例程来启动ListenAndServe。根据Go Documentations。
“ListenAndServe调用Serve”。服务是常规。
ListenAndServe侦听TCP网络地址addr,然后使用处理程序调用Serve来处理传入连接上的请求。接受的连接配置为启用TCP保持活动。处理程序通常为零,在这种情况下使用DefaultServeMux。 https://golang.org/pkg/net/http/#ListenAndServe
func Serve(l net.Listener,handler Handler)错误 Serve接受侦听器l上的传入HTTP连接,为每个连接创建一个新的服务goroutine。服务goroutines读取请求,然后调用处理程序来回复它们。处理程序通常为零,在这种情况下使用DefaultServeMux。 https://golang.org/pkg/net/http/#Serve