当启动无限循环的goroutine时,Golang http服务器阻塞

时间:2014-10-29 07:37:52

标签: http go block goroutine

正如我从golang docs那里学到的,如果我用8个核心(intel i7)的cpu设置runtime.GOMAXPROCS(8),那么启动一个无限循环的goroutine,其他的gorutines不应该被阻塞,因为有很多线程和goprocs。但是当使用net / http包时,这不是真的,无限循环goroutine会在几次调用后阻塞http服务器。 任何人都可以帮忙解释原因吗?

  1. 如果我评论“go infinite loop”行,在服务器之后启动客户端,客户端将输出1000个星号;但如果我启用goroutine,客户端将在打印几个星号后阻止
  2. 我试过在goroutine中添加runtime.LockOSThread(),似乎不起作用
  3. 我的环境:osx 10.10,go版本go1.3.1 darwin / amd64
  4. 服务器代码:

    package main
    
    import (
        "fmt"
        "log"
        "net/http"
        "runtime"
    )
    
    func myHandler(w http.ResponseWriter, req *http.Request) {
        w.Write([]byte("hello"))
    }
    
    func infiniteloop() {
        for {
    
        }
    }
    
    func main() {
        // set max procs for multi-thread executing
        runtime.GOMAXPROCS(runtime.NumCPU())
    
        // print GOMAXPROCS=8 on my computer
        fmt.Println("GOMAXPROCS=", runtime.GOMAXPROCS(-1))
        http.Handle("/", http.HandlerFunc(myHandler))
    
        // uncomment below line cause server block after some requests 
        // go infiniteloop()
        if err := http.ListenAndServe(":8280", nil); err != nil {
            log.Fatal(err)
        }
    }
    

    客户端代码:

    package main
    import (
        "fmt"
        "net/http"
    )
    
    func getOnce() {
        if resp, err := http.Get("http://localhost:8280"); err != nil {
            fmt.Println(err)
            return
        } else {
            defer func() {
                if err := resp.Body.Close(); err != nil {
                    fmt.Println(err)
                }
            }()
            if resp.StatusCode != 200 {
                fmt.Println("error codde:", resp.StatusCode)
                return
            } else {
                fmt.Print("*")
    
            }
        }
    }
    
    func main() {
        for i := 1; i < 1000; i++ {
            getOnce()
            if i%50 == 0 {
                fmt.Println()
            }
        }
    
    }
    

    现在我知道为什么这样的emtpy循环会阻止其他goroutines,但为什么runtime.LockOSThread()也没有帮助?

    func infiniteloop() {
        // add LockOSThread will not help
        runtime.LockOSThread()
        for {
        }
    }
    

    如上所述http://golang.org/pkg/runtime/#LockOSThread,空循环应在独立线程中执行,其他goroutine不应受busy循环的影响。我的理解有什么不对?

2 个答案:

答案 0 :(得分:3)

Go运行时的调度程序is not fully pre-emptive at this time。去1.2改进了问题by occasionally calling into the scheduler on function calls,但是你的例子中的无限循环没有函数调用,所以这没有帮助。

对于无限循环处理程序的实际正文,您可能会看到更好的行为。或者,手动拨打runtime.Gosched可能会对此类情况有所帮助。

答案 1 :(得分:1)

调度程序可能无法抢占这样一个空的“无限”循环。调度程序在上一次发布期间变得越来越好,也许他应该对这样的代码足够好;他肯定对真正的代码足够好。只是不要做这样的废话。