简体   繁体   English

Golang:去goroutine还是不去goroutine?

[英]Golang: to goroutine or not to goroutine?

Many times when developing an http server in Go I have this dilemma. 在Go中开发http服务器时,很多时候我遇到了这个难题。

Assuming I want to respond to the client with http statuscode 200 as fast as possible (and then perform work at the back), this is why I usually do: 假设我想以http statuscode 200尽快响应客户端(然后在后面执行工作),这就是我通常这样做的原因:

I have my main http handler receive the request, I write http 200 to the response, and I send a message over a channel (if I have N workers listening on that channel , I am using a buffered channel of N ): 我让我的主要http处理程序接收到请求,并在响应中写入http 200 ,然后通过一个channel发送一条消息(如果我有N工作人员在该channel上侦听,我正在使用Nbuffered channel ):

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

I have my listeners (fired off on init) listening forever on that channel: 我的听众(在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
        ...
        ...
        ...

Now, my main question is: should I fire off the log(req) function inside a go routine? 现在,我的主要问题是:我应该在go例程中启动log(req)函数吗? ie

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

As far as I can gather, there's no point in opening up a goroutine for every http request in this case. 据我所知,在这种情况下,没有必要为每个http请求打开一个goroutine。

Since the current operation of the log(req) function is mostly sending some data over a channel - that operation is super quick. 由于log(req)函数的当前操作主要是通过channel发送一些数据,因此该操作非常快捷。 The only time when it's not quick - is if the channel blocks. 唯一不快的时间-是channel阻塞了。 Now, if the channel blocks, it has to mean that the worker is blocked. 现在,如果channel阻塞,则必须意味着工作进程已阻塞。 And since the worker listens for messages on the channel forever - if the worker is blocked, it means my machine is truly not capable to produce faster output (the worker does some I/O as you can imagine, but that's also very quick, because the I/O only happens once per minute). 而且由于工作人员永远在信道上侦听消息-如果工作人员被阻止,则意味着我的机器确实无法产生更快的输出(工作人员会执行您可以想象的一些I/O ,但这也非常快,因为I / O每分钟仅发生一次)。

Furthermore, since I have N workers, the channel I am using to send the messages on from the handler is buffered with N , so it only blocks if all N workers are blocked. 此外,由于我有N工作程序,因此我用于从处理程序发送消息的channel将使用N缓冲,因此只有在所有N工作程序均被阻止的情况下,该channel才会阻塞。

Is this correct? 这个对吗? What are the pros and cons of using a goroutine for the log(req) call? 使用goroutine进行log(req)调用的利弊是什么? This handler receives upto 10K requests per second, I am guessing it's not a good idea to open a goroutine for each request. 该处理程序每​​秒接收多达1万个请求,我想为每个请求打开一个goroutine并不是一个好主意。

There's no point in opening up a goroutine for every http request in this case. 在这种情况下,没有必要为每个http请求打开一个goroutine。

That already happens when you use net/http 's Server. 当您使用net/http的Server时已经发生了。 Your handler is invoked in a goroutine of its own. 您的处理程序将在自己的goroutine中被调用。

I am guessing it's not a good idea to open a goroutine for each request. 我想为每个请求打开一个goroutine不是一个好主意。

It's not a bad idea either. 这也不是一个坏主意。 Go's runtime can easily handle hundreds of thousands of goroutines. Go的运行时可以轻松处理数十万个goroutine。

However, if log blocks, you risk timing out on your client, who is waiting to receive a full HTTP response and only doing rw.WriteHeader(200) doesn't constitute one yet. 但是,如果log阻塞,您可能会在等待接收完整HTTP响应并且仅执行rw.WriteHeader(200)的客户端上超时。

To remedy this, you can do something like: 为了解决这个问题,您可以执行以下操作:

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

And it's also probably a good idea to set the Content-Length header of your response to 0 . 将响应的Content-Length标头设置为0也是一个好主意。

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

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