首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用go context.Context

正确使用go context.Context
EN

Stack Overflow用户
提问于 2015-06-19 00:20:00
回答 3查看 4.9K关注 0票数 4

我刚刚读了一篇文章:在Go中构建自己的Web框架,为了在处理程序之间共享值,我选择了context.Context,我用以下方式在处理程序和中间件之间共享值:

代码语言:javascript
复制
type appContext struct {
    db     *sql.DB
    ctx    context.Context
    cancel context.CancelFunc
 }


func (c *appContext)authHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request {
        defer c.cancel() //this feels weird
        authToken := r.Header.Get("Authorization") // this fakes a form
        c.ctx = getUser(c.ctx, c.db, authToken) // this also feels weird
        next.ServeHTTP(w, r)
    }

    return http.HandlerFunc(fn)
}

func (c *appContext)adminHandler(w http.ResponseWriter, r *http.Request) {
    defer c.cancel()
    user := c.ctx.Value(0).(user)
    json.NewEncoder(w).Encode(user)
}

func getUser(ctx context.Context, db *sql.DB, token string) context.Context{
    //this function mimics a database access
    return context.WithValue(ctx, 0, user{Nome:"Default user"})
}

func main() {
    db, err := sql.Open("my-driver", "my.db")
    if err != nil {
        panic(err)
    }
    ctx, cancel := context.WithCancel(context.Background())
    appC := appContext{db, ctx, cancel}
    //....
}

一切都在工作,处理程序比使用大猩猩/上下文加载得更快,所以我的问题是:

  1. 这个方法安全吗?
  2. 真的有必要像我这样做c.cancel()函数吗?
  3. 我可以使用它来实现一个自定义的web框架,使用像struct这样的控制器与模型共享值吗?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-19 05:02:35

您的代码有问题,因为您正在将用户存储到应用程序上下文中。同时有多个用户,它不能工作。上下文必须与不被其他请求覆盖的请求相关。必须将用户存储在请求上下文中。在我的文章中,我使用了以下大猩猩函数:context.Set(r, "user", user)r是请求。

如果您想在应用程序中使用context.Context,应该使用它们的大猩猩包装器(您可以在本文末尾找到它:https://blog.golang.org/context)。

另外,您不需要使用cancel的上下文。对于根上下文来说,context.Background()是可以的。

票数 1
EN

Stack Overflow用户

发布于 2016-06-17 09:48:09

注意: go 1.7.0-rc2确实澄清了一些如何释放与上下文相关的资源 (萨米尔·阿贾玛尼):

有些用户没有意识到用一个Context CancelFunc 创建一个会将一个子树附加到父树上,直到调用 CancelFunc 或取消父树之后才会释放该子树。在包文档的早期就明确这一点,这样学习这个包的人就有了正确的概念模型。

The 现在的文档包括

对服务器的传入请求应该创建一个Context,而对服务器的传出调用应该接受一个Context。 它们之间的函数调用链必须传播Context,可以选择将其替换为使用WithCancelWithDeadlineWithTimeoutWithValue创建的派生Context。 这些Context 值形成一棵树:当 Context 被取消时,由此产生的所有 Contexts 也被取消WithCancelWithDeadlineWithTimeout函数返回派生的ContextCancelFunc。 调用CancelFunc将取消新的Context及其派生的任何上下文,从父树中移除Context,并停止任何相关的计时器。 未能调用CancelFunc会泄漏相关资源,直到父Context被取消或计时器触发为止。

票数 2
EN

Stack Overflow用户

发布于 2019-12-23 18:59:38

上下文包的两个主要用例是:

  1. 用于存储请求作用域值--使用context.WithValue()
  2. 取消-使用context.WithCancel()、context.WithTimeout()、context.WithDeadline()

使用上下文可以形成以context.Background()为根的上下文树。WithValue()、context.WithCancel()、WithTimeout()、WithDeadline()是从根上下文派生的上下文,可以进一步划分。每一个例子都可以清楚地说明什么是正确的使用上下文。本指南以适当的例子提供了上述所有内容的使用。

来源:https://golangbyexample.com/using-context-in-golang-complete-guide/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30928002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档