为什么在处理程序中的goroutine中要复制上下文?

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

Why should I make a copy of a context for goroutines inside handlers?

问题

最近我开始用Go重写一些Python服务,以提高它们的速度,并在gin文档中找到了这一部分内容:https://github.com/gin-gonic/gin#goroutines-inside-a-middleware

所以我理解了这些说明,但我试图理解为什么要这样做?复制上下文的重要性是什么?如果在处理程序中的goroutine中不复制上下文会引入什么问题?

英文:

I recently started rewriting some of my Python services in Go to speed them up and came across this section of the gin documentation:
https://github.com/gin-gonic/gin#goroutines-inside-a-middleware

So I understand the instructions, but I'm trying to understand why? What is the significance of making a copy, and what problem is introduced if I do not make a copy of context for goroutines within handlers?

答案1

得分: 1

Gin-gonic是自身异步的,这使得它非常出色。如果在处理程序中使用并发,很可能会遇到以下情况:

  • Context是一个结构体,它保存了每个请求的数据(参数、由互斥锁保护的键),因此可能会过时。
  • Context为空,这将导致回退到默认的Context。

下面是Context的结构:

type Context struct {
    writermem responseWriter
    Request   *http.Request
    Writer    ResponseWriter

    Params   Params
    handlers HandlersChain
    index    int8
    fullPath string

    engine       *Engine
    params       *Params
    skippedNodes *[]skippedNode

    // This mutex protects Keys map.
    mu sync.RWMutex

    // Keys is a key/value pair exclusively for the context of each request.
    Keys map[string]any

    // Errors is a list of errors attached to all the handlers/middlewares who used this context.
    Errors errorMsgs

    // Accepted defines a list of manually accepted formats for content negotiation.
    Accepted []string

    // queryCache caches the query result from c.Request.URL.Query().
    queryCache url.Values

    // formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
    // or PUT body parameters.
    formCache url.Values

    // SameSite allows a server to define a cookie attribute making it impossible for
    // the browser to send this cookie along with cross-site requests.
    sameSite http.SameSite
}

为了预见这些问题和竞态条件,你必须在处理程序使用并发时使用Copy

以下是gin-gonic存储库中的一句引用:

// Copy returns a copy of the current context that can be safely used outside the request's scope.
// This has to be used when the context has to be passed to a goroutine.

这段代码返回一个当前上下文的副本,可以安全地在请求范围之外使用。当上下文必须传递给goroutine时,必须使用它。

英文:

Gin-gonic is async itself which makes it great.
If you are using concurrency within your handlers it's very likely you will face situation when Context, which is struct goes

  • outdated since it's holding the data from each request (parameters, keys protected by mutex)

  • empty, which will cause a fallback to default Context

here's how it looks like:

type Context struct {
writermem responseWriter
Request   *http.Request
Writer    ResponseWriter

Params   Params
handlers HandlersChain
index    int8
fullPath string

engine       *Engine
params       *Params
skippedNodes *[]skippedNode

// This mutex protects Keys map.
mu sync.RWMutex

// Keys is a key/value pair exclusively for the context of each request.
Keys map[string]any

// Errors is a list of errors attached to all the handlers/middlewares who used this context.
Errors errorMsgs

// Accepted defines a list of manually accepted formats for content negotiation.
Accepted []string

// queryCache caches the query result from c.Request.URL.Query().
queryCache url.Values

// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
// or PUT body parameters.
formCache url.Values

// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests.
sameSite http.SameSite

}

In order to foresee such issues and race conditions - you must use Copy whenever your handlers are using go concurrency

here's a quote from gin-gonic repository:

// Copy returns a copy of the current context that can be safely used outside the request's scope.
// This has to be used when the context has to be passed to a goroutine.

huangapple
  • 本文由 发表于 2022年9月18日 19:55:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/73762584.html
匿名

发表评论

匿名网友

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

确定