英文:
Golang http server blocks when starts a goroutine of infinite-loop
问题
根据你提供的代码和问题,我理解你的问题是关于使用goroutine时为什么空的无限循环会阻塞其他goroutine,以及为什么使用runtime.LockOSThread()
也没有解决这个问题。
首先,让我们来解释为什么空的无限循环会阻塞其他goroutine。在Go语言中,goroutine是由Go运行时调度的,它会在适当的时候进行切换。当一个goroutine在执行一个无限循环时,它会一直占用CPU资源,不会主动让出执行权给其他goroutine。这就导致其他goroutine无法得到执行的机会,从而被阻塞。
至于为什么使用runtime.LockOSThread()
也没有解决这个问题,原因是runtime.LockOSThread()
函数用于将当前goroutine绑定到一个操作系统线程上,以确保该goroutine始终在同一个线程上执行。然而,在你的情况下,无论是否使用runtime.LockOSThread()
,空的无限循环都会一直占用CPU资源,不会主动让出执行权给其他goroutine,因此其他goroutine仍然会被阻塞。
希望能解答你的问题!如果还有其他疑问,请随时提出。
英文:
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. But this is not true when using net/http package, an infinite-loop goroutine will block http server after a few invocations.
Can anyone help to explain why ?
- If i comment the line of "go infinite loop", start client after server, client will output 1000 asterisks; but if i enable the goroutine, client will block after print a few asterisks
- I have tried add runtime.LockOSThread() in the goroutine, it seems that doesn't work
- My Environment: osx 10.10, go version go1.3.1 darwin/amd64
Server code:
<!-- language: lang-golang -->
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:
<!-- language: lang-golang -->
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?
<!-- language: lang-golang -->
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. What's wrong in my understanding?
答案1
得分: 5
Go运行时的调度器目前不是完全抢占式的。Go 1.2通过在函数调用时偶尔调用调度器来改善情况,但是你的示例中的无限循环没有函数调用,所以这并没有帮助。
如果你的无限循环处理程序有实际的函数体,可能会看到更好的行为。或者,在这种情况下,手动调用runtime.Gosched
可能会有所帮助。
英文:
The Go runtime's scheduler is not fully pre-emptive at this time. 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.
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.
答案2
得分: -1
调度程序可能无法抢占这样一个空的“无限”循环。在上一个版本中,调度程序变得越来越好,也许他对于这样的代码来说已经足够好了;对于真实的代码来说,他绝对足够好。只是不要做这样的无意义的事情。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论