使用ListenAndServe的Goroutines可以提高性能吗?

use*_*268 9 concurrency go

我对Go的例程并不是很熟悉,但是因为我正在使用路由器,net/http所以我看到了几次ListenAndServe()被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 {}
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*ier 15

http.ListenAndServe是一个阻止电话.如果你想做一个更多的工作(比如http.ListenAndServe再打一次),你需要把它移到一个单独的goroutine上.这就是他们在这里所做的一切.

他们select{}最后用来阻挡主要的goroutine,因为他们所有的呼叫http.ListenAndServe都在其他goroutine上.如果他们没有打电话select{},该程序将终止,因为main()将返回.

他们可以通过删除select{}和删除go func()最后一个代码块周围的包装器来实现相同的功能.但我怀疑他们是这样做的,所以所有代码都是一致的.

但这与性能无关.

在评论中,您提供了一些类似的其他示例.在第一个例子中:

func main() {
    http.HandleFunc("/", responsehandler.Handler)
    go func() {
      http.ListenAndServe(":8888", nil)
    }()
    fileservice.NewWatcher()
}
Run Code Online (Sandbox Code Playgroud)

这会调用http.ListenAndServe然后调用fileservice.NewWatcher()(阻塞).如果他们没有把话题包裹在goroutine中,fileservice.NewWatcher()就永远不会被召唤.

另外两个 例子是一个常见的样板:

func init() {
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()
}
Run Code Online (Sandbox Code Playgroud)

这将打开调试分析器Web服务器.同样,它是一个goroutine,因此调用init立即返回而不是阻塞.这种特殊情况允许调用者只是import _ "profiling""神奇地"获得调试分析器Web服务器.