如何创建Go上下文的副本(如果需要,则为副本),该副本包含原始文件中存储的所有值,但是原始文件不会被取消?
在我看来,这确实是一个有效的用例。假设我有一个http请求,并且在响应返回给客户端之后取消了它的上下文,并且我需要在此请求的结尾处在一个单独的goroutine中运行一个异步任务,该例程很可能会超过父上下文。
func Handler(ctx context.Context) (interface{}, error) {
result := doStuff(ctx)
newContext := howDoICloneYou(ctx)
go func() {
doSomethingElse(newContext)
}()
return result
}
任何人都可以建议应该怎么做吗?
当然,我可以跟踪可能放在上下文中的所有值,创建一个新的背景ctx,然后仅遍历每个可能的值并进行复制...但这似乎很乏味,并且很难在一个大型代码库。
答案 0 :(得分:5)
由于context.Context是一个接口,因此您只需创建自己的实现就永远不会取消它:
import (
"context"
"time"
)
type noCancel struct {
ctx context.Context
}
func (c noCancel) Deadline() (time.Time, bool) { return time.Time{}, false }
func (c noCancel) Done() <-chan struct{} { return nil }
func (c noCancel) Err() error { return nil }
func (c noCancel) Value(key interface{}) interface{} { return c.ctx.Value(key) }
// WithoutCancel returns a context that is never canceled.
func WithoutCancel(ctx context.Context) context.Context {
return noCancel{ctx: ctx}
}
答案 1 :(得分:4)
任何人都可以建议应该怎么做吗?
是的。不要这样做。
如果您需要其他上下文,例如为您的异步后台任务创建一个新上下文。您传入的上下文和您的后台任务之一是不相关,因此您不得尝试重用传入的上下文。
如果不相关的新上下文需要原始数据,请执行以下操作:复制所需内容并添加新内容。