Golang的HTTP服务器在启动无限循环的goroutine时会阻塞。

huangapple go评论75阅读模式
英文:

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 ?

  1. 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
  2. I have tried add runtime.LockOSThread() in the goroutine, it seems that doesn't work
  3. My Environment: osx 10.10, go version go1.3.1 darwin/amd64

Server code:
<!-- language: lang-golang -->

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;runtime&quot;
)

func myHandler(w http.ResponseWriter, req *http.Request) {
	w.Write([]byte(&quot;hello&quot;))
}

func infiniteloop() {
	for {

	}
}

func main() {
	// set max procs for multi-thread executing
	runtime.GOMAXPROCS(runtime.NumCPU())

	// print GOMAXPROCS=8 on my computer
	fmt.Println(&quot;GOMAXPROCS=&quot;, runtime.GOMAXPROCS(-1))
	http.Handle(&quot;/&quot;, http.HandlerFunc(myHandler))
    
    // uncomment below line cause server block after some requests 
	// go infiniteloop()
	if err := http.ListenAndServe(&quot;:8280&quot;, nil); err != nil {
		log.Fatal(err)
	}
}

Client code:
<!-- language: lang-golang -->

package main
import (
	&quot;fmt&quot;
	&quot;net/http&quot;
)

func getOnce() {
	if resp, err := http.Get(&quot;http://localhost:8280&quot;); 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(&quot;error codde:&quot;, resp.StatusCode)
			return
		} else {
			fmt.Print(&quot;*&quot;)

		}
	}
}

func main() {
	for i := 1; i &lt; 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.

huangapple
  • 本文由 发表于 2014年10月29日 15:37:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/26624959.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定