取消进行中的操作

您可以使用 Go context.Context 管理进行中的操作。Context 是一个标准的 Go 数据值,它可以报告它所代表的整个操作是否已被取消且不再需要。通过在应用程序的函数调用和服务之间传递 context.Context,这些函数和服务可以在其处理不再需要时提前停止工作并返回错误。有关 Context 的更多信息,请参阅Go 并发模式:Context

例如,您可能希望

  • 结束长时间运行的操作,包括耗时过长的数据库操作。
  • 从其他地方传播取消请求,例如当客户端关闭连接时。

许多针对 Go 开发人员的 API 都包含接受 Context 参数的方法,这使得您可以在整个应用程序中更轻松地使用 Context

在超时后取消数据库操作

您可以使用 Context 设置超时或截止时间,在该时间之后操作将被取消。要派生具有超时或截止时间的 Context,请调用 context.WithTimeoutcontext.WithDeadline

以下超时示例中的代码派生了一个 Context 并将其传递给 sql.DBQueryContext 方法。

func QueryWithTimeout(ctx context.Context) {
    // Create a Context with a timeout.
    queryCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    // Pass the timeout Context with a query.
    rows, err := db.QueryContext(queryCtx, "SELECT * FROM album")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    // Handle returned rows.
}

当一个上下文从外部上下文派生时,例如本例中 queryCtxctx 派生,如果外部上下文被取消,那么派生上下文也会自动取消。例如,在 HTTP 服务器中,http.Request.Context 方法返回与请求关联的上下文。如果 HTTP 客户端断开连接或取消 HTTP 请求(在 HTTP/2 中可能),该上下文将被取消。将 HTTP 请求的上下文传递给上面的 QueryWithTimeout 将导致数据库查询提前停止,**如果**整个 HTTP 请求被取消,**或者**如果查询花费了超过五秒钟。

注意:在创建具有超时或截止时间的新 Context 时,请务必延迟调用返回的 cancel 函数。这会在包含函数退出时释放新 Context 持有的资源。它还会取消 queryCtx,但当函数返回时,应该没有任何东西再使用 queryCtx 了。