每个 HTTP 请求应该有一个新的 datastore.Client 吗?

Should there be a new datastore.Client per HTTP request?

official Go documentation on the datastore package(GCP 数据存储服务的客户端库)具有以下用于演示的代码片段:

type Entity struct {
    Value string
}

func main() {
    ctx := context.Background()

    // Create a datastore client. In a typical application, you would create
    // a single client which is reused for every datastore operation.
    dsClient, err := datastore.NewClient(ctx, "my-project")
    if err != nil {
        // Handle error.
    }

    k := datastore.NameKey("Entity", "stringID", nil)
    e := new(Entity)
    if err := dsClient.Get(ctx, k, e); err != nil {
        // Handle error.
    }

    old := e.Value
    e.Value = "Hello World!"

    if _, err := dsClient.Put(ctx, k, e); err != nil {
        // Handle error.
    }

    fmt.Printf("Updated value from %q to %q\n", old, e.Value)
}

正如您所看到的,它指出 datastore.Client 理想情况下应该只在应用程序中实例化一次。现在鉴于 datastore.NewClient 函数需要一个 context.Context 对象,这是否意味着它应该只在每个 HTTP 请求中实例化一次,或者它是否可以安全地使用 context.Background() 对象全局实例化一次?

每个操作再次需要一个 context.Context 对象(例如 dsClient.Get(ctx, k, e))那么应该使用 HTTP 请求的上下文吗?

我是 Go 的新手,真的找不到任何在线资源可以用真实世界的例子和实际的最佳实践模式很好地解释这样的事情。

您可以使用任何 context.Context for the datastore client creation, it may be context.Background(),完全没问题。客户端创建可能很长,它可能需要连接到远程服务器、进行身份验证、获取配置等。如果您的用例时间有限,您可以传递一个超时上下文来中止操作。此外,如果创建时间比您拥有的时间长,您可以使用带有取消的上下文并随意中止任务。这些只是您可能会或可能不会使用的选项。但是 "tools" 是通过 context.Context.

给出的

稍后当您在处理 (HTTP) 客户端请求期间使用 datastore.Client 时,使用请求的上下文是合理的,因此如果请求被取消,那么它的上下文也会被取消,数据存储操作也会被取消您正确地发出,因为如果客户看不到结果,那么完成查询就没有意义。提前终止查询您可能不会最终使用某些资源(例如数据存储读取),并且您可能会降低服务器的负载(通过中止其结果不会被发送回客户端的作业)。