我对Go的例程不是很熟悉,但是由于我正在使用net/http
的路由器,因此我几次看到ListenAndServe()
被go例程包装了。
服务器需要能够开箱即用地同时处理多个请求,以提高效率。那么为什么将go例程用作“轻量级线程”呢?
并发是否提供任何优势?
这是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 {}
}
最佳答案
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()
。其他two examples是常见的样板:
func init() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
}
这将打开调试事件探查器Web服务器。同样,这是一个goroutine,因此调用
init
会立即返回而不是阻塞。这种特殊情况允许调用者仅添加import _ "profiling"
并“神奇地”获得调试概要分析器Web服务器。关于concurrency - 带有ListenAndServe的Goroutine可以提高性能吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30487703/