- 实现思路:
- 创建一个
context.Context
和 context.CancelFunc
。CancelFunc
用于在满足某个条件时取消 context.Context
。
- 在每个需要协作的
goroutine
中,传入 context.Context
,并在 goroutine
中定期检查 context.Context
的 Done()
通道。当 Done()
通道可读时,意味着 context
被取消,此时进行清理工作并退出 goroutine
。
- 示例代码如下:
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d cleaning up and exiting\n", id)
return
default:
fmt.Printf("Worker %d is working\n", id)
time.Sleep(1 * time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
numWorkers := 3
for i := 0; i < numWorkers; i++ {
go worker(ctx, i)
}
// 模拟某个条件满足
time.Sleep(3 * time.Second)
cancel()
time.Sleep(2 * time.Second)
}
- context数据结构有助于实现此功能的特性:
- 取消机制:
context.WithCancel
函数返回的 CancelFunc
允许在外部方便地取消 context
,从而通知所有依赖该 context
的 goroutine
。一旦 CancelFunc
被调用,context.Context
的 Done()
通道会被关闭,所有监听此通道的 goroutine
可以感知到取消信号。
- 传递性:
context.Context
可以在不同的 goroutine
之间传递,确保所有相关的 goroutine
都能接收到取消信号。这使得在复杂的并发程序中,能够统一管理多个 goroutine
的生命周期。
- 超时控制:除了
WithCancel
,context
还有 WithTimeout
等函数,可以设置一个超时时间。当超时时间到达时,context
也会被取消,这在某些需要限制执行时间的场景下非常有用,同样有助于实现 goroutine
的清理和退出。