面试题答案
一键面试思路
- 分层设计:为不同层级的任务组创建不同的context,当上层context取消时,下层所有相关任务的context也能相应取消。例如,将任务按功能模块划分为不同组,每个组有独立的context,由一个总的context管理这些组的context。
- 使用select语句:在任务执行函数中,通过
select
语句监听context的取消信号。这样任务可以在接收到取消信号时,及时停止执行。 - 减少不必要的等待:避免在任务中出现长时间阻塞且无法响应取消信号的操作。若存在如网络请求等可能阻塞的操作,使用支持取消的接口(如
http.Request
中设置context
)。 - 避免竞态条件:使用
sync.Mutex
或sync.RWMutex
来保护共享资源,确保在context取消过程中,对共享资源的访问是安全的。同时,合理使用channel
进行任务间的通信,避免多个任务同时修改同一数据。
代码实现要点
- 创建context:
ctx, cancel := context.WithCancel(context.Background())
如果任务有执行时间限制,可使用context.WithTimeout
或context.WithDeadline
。
2. 任务执行函数:
func task(ctx context.Context, taskID int) {
for {
select {
case <-ctx.Done():
// 清理资源,如关闭文件、数据库连接等
return
default:
// 执行任务逻辑
println("Task", taskID, "is running")
}
}
}
- 启动任务:
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
task(ctx, id)
}(i)
}
- 取消任务:
// 当满足某个条件时取消任务
cancel()
wg.Wait()
- 保护共享资源: 若任务间存在共享资源,例如一个共享的计数器:
var counter int
var mu sync.Mutex
func task(ctx context.Context, taskID int) {
for {
select {
case <-ctx.Done():
return
default:
mu.Lock()
counter++
mu.Unlock()
}
}
}