Golang http服务器块启动一个无限循环的goroutine时 [英] Golang http server blocks when starts a goroutine of infinite-loop

查看:773
本文介绍了Golang http服务器块启动一个无限循环的goroutine时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如我从golang文档中学到的,如果我使用8核cpu(intel i7)设置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达尔文/ amd64

服务器代码:

 包主

导入(
fmt
log
net / http
runtime


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

func infiniteloop(){
for {




func main(){
//设置多线程执行的最大进程
runtime.GOMAXPROCS(runtime.NumCPU())

//在我的电脑上打印GOMAXPROCS = 8
fmt.Println(GOMAXPROCS =,runtime.GOMAXPROCS(-1))
http.Handle(/,http。 HandlerFunc(myHandler))

//在下面一行取消注释会导致某些请求后的服务器块ests
//去infiniteloop()
如果err:= http.ListenAndServe(:8280,nil); err!= nil {
log.Fatal(err)
}
}

客户端代码

 包主
导入(
fmt
net / http


func getOnce(){
if resp,err:= http.Get(http ://本地主机:8280\" ); err!= nil {
fmt.Println(err)
return
} else {
如果err:= resp.Body.Close ); err!= nil {
fmt.Println(err)
}
}()
如果resp.StatusCode!= 200 {
fmt.Println(error codde :,resp.StatusCode)
return
} else {
fmt.Print(*)

}
}
}

func main(){
for i:= 1;我< 1000; i ++ {
getOnce()
if i%50 == 0 {
fmt.Println()
}
}

}




$ b

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

  func infiniteloop(){
//添加LockOSThread不会帮助
runtime.LockOSThread()
用于{
}
}

http://golang.org/pkg/runtime/#LockOSThread 提到,空循环应该在独立线程中执行,其他的goroutine不应该受繁忙循环的影响。我的理解出了什么问题?

解决方案

Go运行时的调度程序目前还没有完全抢占先机。通过偶尔调用函数调用的调度程序,Go 1.2改进了 的事务,但是无限循环你的例子没有函数调用,所以这没有帮助。



对于你的无限循环处理程序,你可能会看到更好的行为。或者,您也可以手动拨打 runtime.Gosched 可能有助于这样的情况。


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:

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?

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?

解决方案

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.

这篇关于Golang http服务器块启动一个无限循环的goroutine时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆