取消进行中的操作
您可以使用 Go context.Context
管理进行中的操作。Context
是一个标准的 Go 数据值,它可以报告它所代表的整个操作是否已被取消且不再需要。通过在应用程序的函数调用和服务之间传递 context.Context
,这些函数和服务可以在其处理不再需要时提前停止工作并返回错误。有关 Context
的更多信息,请参阅Go 并发模式:Context。
例如,您可能希望
- 结束长时间运行的操作,包括耗时过长的数据库操作。
- 从其他地方传播取消请求,例如当客户端关闭连接时。
许多针对 Go 开发人员的 API 都包含接受 Context
参数的方法,这使得您可以在整个应用程序中更轻松地使用 Context
。
在超时后取消数据库操作
您可以使用 Context
设置超时或截止时间,在该时间之后操作将被取消。要派生具有超时或截止时间的 Context
,请调用 context.WithTimeout
或 context.WithDeadline
。
以下超时示例中的代码派生了一个 Context
并将其传递给 sql.DB
的 QueryContext
方法。
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.
}
当一个上下文从外部上下文派生时,例如本例中 queryCtx
从 ctx
派生,如果外部上下文被取消,那么派生上下文也会自动取消。例如,在 HTTP 服务器中,http.Request.Context
方法返回与请求关联的上下文。如果 HTTP 客户端断开连接或取消 HTTP 请求(在 HTTP/2 中可能),该上下文将被取消。将 HTTP 请求的上下文传递给上面的 QueryWithTimeout
将导致数据库查询提前停止,**如果**整个 HTTP 请求被取消,**或者**如果查询花费了超过五秒钟。
注意:在创建具有超时或截止时间的新 Context
时,请务必延迟调用返回的 cancel
函数。这会在包含函数退出时释放新 Context
持有的资源。它还会取消 queryCtx
,但当函数返回时,应该没有任何东西再使用 queryCtx
了。