Golang:goroutine还是不goroutine?

时间:2015-09-11 11:46:14

标签: multithreading http go goroutine

很多时候,在Go中开发http服务器时,我遇到了这种困境。

假设我想尽快用http statuscode 200回复客户端(然后在后面执行工作),这就是我通常做的原因:

我的主http处理程序接收请求,我将http 200写入响应,然后通过channel发送消息(如果我有N个工作人员正在监听channel {1}},我使用buffered channel N}:

func myHttpHandler(rw http.ResponseWriter, req *http.Request) {
    rw.WriteHeader(200)
    log(req)
}

func log(req *http.Request) {
    msg := createLog(req)
    if msg != nil {
        channel <- msg
    }
}

我让我的听众(在init上解雇)在该频道上永远倾听:

func init() {
    for i := 0; i < workerCount; i++ {
        go worker(i, maxEntrySize, maxBufferSize, maxBufferTime)
    }
}

func worker(workerID int, maxEntrySize int, maxBufferSize int, maxBufferTime time.Duration) {
    for {
        entry := <-channel
        ...
        ...
        ...

现在,我的主要问题是:我应该在go例程中启动log(req)函数吗?即。

func myHttpHandler(rw http.ResponseWriter, req *http.Request) {
    rw.WriteHeader(200)
    go func() { log(req) } ()
}

据我所知,在这种情况下,为每个http请求打开goroutine是没有意义的。

由于log(req)函数的当前操作主要是通过channel发送一些数据 - 该操作非常快。它不快的唯一时间是channel阻止。现在,如果channel阻止,则必须表示该工作程序被阻止。并且由于工作人员永远在通道上监听消息 - 如果工作人员被阻止,这意味着我的机器确实无法产生更快的输出(工作人员会按照您的想象做一些I/O但是那个&#39;也非常快,因为I / O每分钟只发生一次)。

此外,由于我有N个工作者,我用来从处理程序发送消息的channelN进行缓冲,所以它只会阻塞所有N工人被阻止了。

这是对的吗?使用goroutine进行log(req)通话的优缺点是什么?这个处理程序每​​秒收到高达10K的请求,我猜测为每个请求打开goroutine不是一个好主意。

1 个答案:

答案 0 :(得分:4)

  

在这种情况下,为每个http请求打开goroutine是没有意义的。

使用net/http服务器时已经发生这种情况。你的处理程序是在它自己的goroutine中调用的。

  

我猜测为每个请求打开一个goroutine并不是一个好主意。

这也不是一个坏主意。 Go的运行时可以轻松处理数十万个goroutines。

但是,如果log阻止,您可能会在您的客户端上超时,他们正在等待接收完整的HTTP响应,并且仅rw.WriteHeader(200)尚未构成一个。

要解决此问题,您可以执行以下操作:

if cr, ok := rw.(io.Closer) {
    cr.Close()
}

将响应的Content-Length标题设置为0也是个不错的主意。