简体   繁体   English

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

[英]Golang http server blocks when starts a goroutine of infinite-loop

As i learned from golang docs, if i set runtime.GOMAXPROCS(8) with a cpu of 8 cores (intel i7), then start a goroutine of infinite-loop, other gorutines should not be blocked because there are engough threads and goprocs. 正如我从golang docs那里学到的,如果我用8个核心(intel i7)的cpu设置runtime.GOMAXPROCS(8),然后启动无限循环的goroutine,其他gorutines不应该被阻止,因为有很多线程和goprocs。 But this is not true when using net/http package, an infinite-loop goroutine will block http server after a few invocations. 但是当使用net / http包时,这不是真的,无限循环goroutine会在几次调用后阻塞http服务器。 Can anyone help to explain why ? 任何人都可以帮忙解释原因吗?

  1. If i comment the line of "go infinite loop", start client after server, client will output 1000 asterisks; 如果我评论“go infinite loop”行,在服务器后启动客户端,客户端将输出1000个星号; but if i enable the goroutine, client will block after print a few asterisks 但如果我启用goroutine,客户端将在打印几个星号后阻止
  2. I have tried add runtime.LockOSThread() in the goroutine, it seems that doesn't work 我试过在goroutine中添加runtime.LockOSThread(),似乎不起作用
  3. My Environment: osx 10.10, go version go1.3.1 darwin/amd64 我的环境:osx 10.10,go版本go1.3.1 darwin / amd64

Server code: 服务器代码:

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)
    }
}

Client code: 客户代码:

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()
        }
    }

}

Now i know why such emtpy loop block other goroutines, but why runtime.LockOSThread() doesn't help either? 现在我知道为什么这样的emtpy循环阻止其他goroutines,但为什么runtime.LockOSThread()也无济于事?

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

As http://golang.org/pkg/runtime/#LockOSThread mentioned, the empty loop should be executed in an standalone thread, and other goroutines should not be impacted by the busy loop. 正如http://golang.org/pkg/runtime/#LockOSThread所提到的,空循环应该在一个独立的线程中执行,而其他goroutine不应该受到busy循环的影响。 What's wrong in my understanding? 我的理解有什么不对?

The Go runtime's scheduler is not fully pre-emptive at this time . Go运行时的调度程序目前还没有完全先发制人 Go 1.2 improved matters by occasionally calling into the scheduler on function calls , but the infinite loops in your example have no function calls so this doesn't help. 通过在函数调用中偶尔调用调度程序来改进1.2改进的问题,但是示例中的无限循环没有函数调用,所以这没有帮助。

With an actual body to your infinite loop handlers, you may see better behaviour. 通过实体到无限循环处理程序,您可能会看到更好的行为。 Alternatively, a manual call to runtime.Gosched may help in cases like this. 或者,手动调用runtime.Gosched可能会有所帮助。

The scheduler might not be able to preempt such an empty "infinite" loop. 调度程序可能无法抢占这种空的“无限”循环。 The scheduler got better and better during the last release, maybe he should be good enough for such code; 调度程序在上一次发布期间变得越来越好,也许他应该对这些代码足够好; he definitely is good enough for real code. 他肯定对真正的代码足够好。 Just don't do such nonsense. 只是不要做这样的废话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM