我对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/

10-10 06:27