Golang的’defer’导致API响应的发送(接收)延迟。

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

Golang 'defer' causing delay in sending(receiving) API response

问题

我创建了一个API,在处理请求并发送响应后,启动一个后台goroutine来记录一些消息。我使用了'defer'来在处理API请求后执行goroutine。

以下是代码片段:

发送响应的伪代码:

{
  ...
  res.Header().Add("Content-Type", "application/json")
  json.NewEncoder(res).Encode(response)
}

响应结构体:

type Response struct {
   StatusCode int16  `json:"statusCode"`
   Message    string `json:"message"`
}

API主体:

{ 
 ...
 defer logMsgs()
 sendAPIResponse()
 return
}

记录消息的伪代码:

func logMsgs(){
   time.Sleep(10*time.Seconds)
   wg := sync.Waitgroup{}
   wg.Add(1)
   go func(){
      for i = 1 to 10
         print(i)
      wg.Done()
   }()
   wg.Wait()
}

期望的结果是在收到API响应后,经过几秒钟(这里是10秒),从1到10打印出'i'的值。

但实际结果是在10秒后才收到API响应。

根据我的理解,defer函数在周围(或当前/封闭)函数终止或返回后调用。

所以我必须先收到API响应,然后才能记录'i'的值。但在我的情况下,我在一些秒钟(10秒)后才收到响应。如果'i'的值很大,这将是一个重大问题。

如果有人能解释这种异常行为并提供可能的解决方案,将会很有帮助。谢谢。

英文:

I have created an API, which after processing the request sends a response and starts a background goroutine which logs some messages. I have used 'defer' to execute goroutine after the API request has been handled.

Following are the code snippets:

sendResponse Pseudocode:

{
  ...
  res.Header().Add("Content-Type", "application/json")
  json.NewEncoder(res).Encode(response)
}

Response struct:

type Response struct {
   StatusCode int16  `json:"statusCode"`
   Message    string `json:"message"`
}

API Body:

{ 
 ...
 defer logMsgs()
 sendAPIResponse()
 return
}

logMsgs Pseudocode:

func logMsgs(){
   time.Sleep(10*time.Seconds)
   wg := sync.Waitgroup{}
   wg.Add(1)
   go func(){
      for i = 1 to 10
         print(i)
      wg.Done()
   }()
   wg.Wait()
}

Expected Outcome is to receive the API response and after few seconds(here 10s) value of 'i' is printed from 1 to 10.

But in Actual Outcome, API response is received after 10s.

As per my understanding defer functions are called after the surrounding (or current/enclosing) function terminates or returns.

So I must first receive the API response and later values of 'i' must be logged. But in my case I am receiving the response after some seconds(10s) are elapsed. This would be a major issue if value of 'i' is quite large.

It will be helpful if someone explains this abnormal behavior and provides possible solutions.
Thanks

答案1

得分: 1

我已经使用了defer来在处理完API请求后执行goroutine。

defer并不会启动一个goroutine,它会在调用的goroutine上执行延迟函数。而且很有可能响应被缓存,直到从处理程序返回之前写入的数据才不会被刷新。

如果你想在一个新的goroutine中执行日志记录,可以使用go关键字,像这样:

defer func() {
    go logMsgs()
}()
sendAPIResponse()
return

但是请注意,在处理程序返回后,启动的goroutine无法访问请求和响应特定的对象,因为它们可能会被重用于新的请求。所以在处理程序返回后,保存/传递日志记录器所需的所有内容,以便安全地在处理程序返回后使用它们。

英文:

> I have used 'defer' to execute goroutine after the API request has been handled.

defer does not launch a goroutine. It executes the deferred function on the calling goroutine. And it's very much possible that the response is cached and data written to it is not flushed until you return from your handler.

If you want to execute the logging in a new goroutine, use the go keyword like this:

defer func() {
    go logMsgs()
}()
sendAPIResponse()
return

Note however that after returning from the handler, launched goroutines cannot access request and response specific objects as they may be reused for new requests. So save / pass everything that the logger needs in order to safely use them after returning from the handler.

huangapple
  • 本文由 发表于 2022年4月16日 21:21:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/71894224.html
匿名

发表评论

匿名网友

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

确定