Golang:去协程还是不去协程?

orc*_*man 2 multithreading http go goroutine

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

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

我让我的主要 http 处理程序接收请求,我写http 200响应,然后我通过 a 发送一条消息channel(如果我有N工作人员在听channel,我正在使用 a buffered channelof 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
    }
}
Run Code Online (Sandbox Code Playgroud)

我让我的听众(在 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
        ...
        ...
        ...
Run Code Online (Sandbox Code Playgroud)

现在,我的主要问题是:我应该log(req)在 go 例程中触发函数吗?IE

func myHttpHandler(rw http.ResponseWriter, req *http.Request) {
    rw.WriteHeader(200)
    go func() { log(req) } ()
}
Run Code Online (Sandbox Code Playgroud)

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

由于该log(req)函数的当前操作主要是通过 a 发送一些数据channel- 该操作非常快。唯一不快的时候 - 是如果channel块。现在,如果channel阻塞,则必须意味着工人被阻塞。并且由于工作人员永远在通道上侦听消息 - 如果工作人员被阻止,则意味着我的机器确实无法产生更快的输出(工作人员可以I/O像您想象的那样做一些事情,但这也非常快,因为我/ O 每分钟只发生一次)。

此外,由于我有N工人,channel我用来从处理程序发送消息的 被缓冲N,因此只有在所有N工人都被阻塞时才会阻塞。

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

thw*_*hwd 5

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

当您使用net/http的服务器时,这已经发生了。你的处理程序在它自己的 goroutine 中被调用。

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

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

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

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

if cr, ok := rw.(io.Closer) {
    cr.Close()
}
Run Code Online (Sandbox Code Playgroud)

Content-Length将响应的标题设置为0.