上下文.TODO() 或上下文.背景(),我应该更喜欢哪一个



我目前正在将我们的代码从全局符号包迁移到 mongo-driver,不确定我应该在哪里使用context.TODO()context.Background(),这真的很令人困惑,我知道它都返回非 nil 空,所以我应该在主函数和init()函数中使用context.Background()吗?并在其他地方使用context.TODO()?谁能帮忙?

尝试检查我应该使用哪个参数context.TODO()context.Background().

检查他们的文档:

context.Background()

func Background() Context

背景返回一个非 nil 的空上下文。它永远不会被取消,没有值,也没有截止日期。它通常由 main 函数、初始化和测试使用,并用作传入请求的顶级上下文。

context.TODO()

func TODO() Context

TODO 返回一个非 nil 的空上下文。代码应使用上下文。当不清楚要使用哪个上下文或尚不可用时(因为周围的函数尚未扩展为接受上下文参数),则执行 TODO。

根据文档,当您需要一个上下文但您还没有上下文并且不知道该使用什么时,请使用context.TODO().这正是您的情况,使用context.TODO()正确记录这一点。此外,静态分析工具和 IDE 可能会提供支持发现这些上下文,并在以后向您发出警告以解决此问题。

另请注意,如果在必须使用 mongo 驱动程序时确实有上下文,请考虑使用该上下文,或从中派生一个新上下文。

例如,如果您正在编写一个需要查询某些文档的 HTTP 处理程序,则 HTTP 请求http.Request已经有一个可以使用Request.Context()访问的上下文。这是调用需要上下文的其他 API 函数时要使用的主要候选项。

你可能会问,为什么?因为当 HTTP 客户端放弃/中止请求时,请求的上下文被取消,这意味着无论你做什么,客户端都不会收到它,所以例如,如果 HTTP 处理程序只提供信息,你不妨中止生成它,节省一些资源。因此,如果在执行MongoDB查询时取消了请求上下文,您也可以取消查询,因为无论如何您都不需要(不会处理)结果。取消传递给查询执行的上下文(例如Collection.Find())是告诉MongoDB服务器尽可能取消查询的方法(因为您不需要结果)。

因此,在这种情况下使用请求上下文可以在HTTP服务器和MongoDB服务器上节省一些CPU时间和内存。

另一个例子:假设你必须在10秒内产生HTTP响应(可能是平台限制),在此期间你必须执行MongoDB操作,并且你必须对结果进行后处理,这需要4秒。在这种情况下,如果 MongoDB 操作花费的时间超过 6 秒,您将无法完成后处理以适应 10 秒的限制。因此,如果MongoDB操作在6秒内未完成,则不妨取消该操作。

解决此问题的一种简单方法是派生一个超时为 6 秒的上下文:

ctx, cancel := context.WithTimeout(r.Context(), 6 * time.Second)
defer cancel()
// ctx automatically times out after 6 seconds
curs, err := c.Find(ctx, bson.M{"some": "filter"})

在此示例中,ctx将在 6 秒后超时,因此如果c.Find()操作未完成,传递的ctx将发出可以取消的信号(在这种情况下将返回错误)。由于ctx是从r.Context()派生的,如果请求的上下文更早被取消(例如HTTP客户端中止),ctx也会被取消。

现在,假设您不是在编写 HTTP 处理程序,而是在编写一些其他代码(独立应用程序、后台工作程序等),您可能没有上下文,但您有不想等待超过 30 秒的查询的标准。这是一个典型的示例,您可以在其中使用 30 秒超时从context.Background()派生上下文:

ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second)
defer cancel()
// ctx automatically times out after 30 seconds
curs, err := c.Find(ctx, bson.M{"some": "filter"})

如果查询在 30 秒内完成,一切正常,您可以使用结果。否则,上下文将在 30 秒后取消,因此c.Find()也将(可能)返回错误。

context.TODO

代码应使用上下文。当不清楚要使用哪个上下文或尚不可用时(因为周围的函数尚未扩展为接受上下文参数),则执行 TODO。

context.Background

背景返回一个非 nil 的空上下文。它永远不会被取消,没有值,也没有截止日期。它通常由 main 函数、初始化和测试使用,并用作传入请求的顶级上下文。

TODO是一个占位符,用于明确代码将来应使用更合适的上下文进行更新,但尚不可用。 当不需要此类指示并且您只需要一个没有值或取消的空根上下文时,将使用Background。它们返回的值是相同的;唯一的区别是语义,因为人们可能会扫描代码以查找TODO上下文(或使用 linter 执行此操作)作为需要更新/寻址的地方。

相关内容