Go语言中的context包提供了一种在不同Goroutines之间传递取消信号、超时、截止日期和请求范围值的方法,用于更好地管理并控制并发操作。
WithCancel
在这个示例中,我们首先创建了一个带有取消功能的context,然后启动了一个Goroutine来执行某项工作,这个Goroutine在工作过程中定期检查ctx.Done()通道,如果接收到取消信号,则停止工作。在main函数中,我们等待了一段时间,然后调用cancel函数,以发送取消信号。在取消信号发送后,Goroutine会收到信号并停止工作。
package main import ( "context" "fmt" "time" ) func doSomething(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("Received cancellation signal. Cleaning up...") return default: // Simulate some work fmt.Println("Working...") time.Sleep(1 * time.Second) } } } func main() { // 创建一个带有取消功能的context ctx, cancel := context.WithCancel(context.Background()) // 启动一个Goroutine执行某项工作,传入context go doSomething(ctx) // 等待一段时间,然后取消工作 time.Sleep(10 * time.Second) cancel() // 调用cancel函数来发送取消信号 // 等待一段时间,以观察工作是否被取消 time.Sleep(5 * time.Second) } |
WithTimeout
在这个示例中,我们首先创建一个带有超时控制的 context,并设置最大执行时间为 5 秒。然后,我们启动一个 Goroutine 来执行某项工作。主函数休眠 10 秒以等待 Goroutine 的完成或超时。由于 context.WithTimeout 设置了最大执行时间为 5 秒,因此 Goroutine 会在 5 秒后收到超时信号,结束工作。
context.WithTimeout 可以用于控制并发操作的执行时间,以确保它们不会无限期地运行。这在处理网络请求、I/O 操作、调用外部服务等场景中特别有用,以避免操作长时间阻塞并占用资源。
package main import ( "context" "fmt" "time" ) func doSomething(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("Received cancellation signal. Cleaning up...") return case <-time.After(1 * time.Second): fmt.Println("Task completed.") } } } func main() { // 创建一个带有超时控制的 context,设置最大执行时间为 5 秒 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 一定要记得调用 cancel,确保资源得以释放 // 启动一个 Goroutine 执行某项工作,传入 context go doSomething(ctx) // 主函数休眠 10 秒,以等待 Goroutine 完成或超时 time.Sleep(10 * time.Second) } |
WithValue
package main import ( "context" "fmt" "time" ) func processRequest(ctx context.Context) { // 从context中获取请求ID requestID, ok := ctx.Value("requestKey").(int) if !ok { fmt.Println("Request ID not found in context.") return } fmt.Printf("Processing request with ID %d\n", requestID) } func main() { // 创建一个带有请求ID的context ctx := context.WithValue(context.Background(), "requestKey", 12345) // 在另一个函数中使用context go processRequest(ctx) // 主函数休眠一段时间,以确保Goroutine有时间运行 time.Sleep(5 * time.Second) } |
WithDeadline
context.WithDeadline 方法用于创建一个带有截止日期的 context,允许你设置一个操作的最后截止日期,如果操作在截止日期之后仍未完成,context 会自动取消它。
package main import ( "context" "fmt" "time" ) func doSomething(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("Received cancellation signal. Cleaning up...") return case <-time.After(1 * time.Second): fmt.Println("Task completed.") } } } func main() { // 设置截止日期为当前时间加 5 秒 deadline := time.Now().Add(5 * time.Second) // 创建一个带有截止日期的 context ctx, cancel := context.WithDeadline(context.Background(), deadline) defer cancel() // 一定要记得调用 cancel,确保资源得以释放 // 启动一个 Goroutine 执行某项工作,传入 context go doSomething(ctx) // 主函数休眠 10 秒,以等待 Goroutine 完成或截止日期到达 time.Sleep(10 * time.Second) } |
context继承
这个例子5秒后结束程序。
package main import ( "context" "fmt" "time" ) func doSomething(ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("Received cancellation signal. Cleaning up...") return default: // Simulate some work fmt.Println("Working...") time.Sleep(1 * time.Second) } } } func main() { // 创建一个带有取消功能的context rootCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithCancel(rootCtx) // 启动一个Goroutine执行某项工作,传入context go doSomething(ctx) // 等待一段时间,然后取消工作 time.Sleep(10 * time.Second) cancel() // 调用cancel函数来发送取消信号 // 等待一段时间,以观察工作是否被取消 time.Sleep(5 * time.Second) } |