面试题答案
一键面试在Go语言中,context
包提供了一种优雅的方式来实现多协程任务的取消机制。以下是具体的代码示例及解释:
package main
import (
"context"
"fmt"
"time"
)
// 模拟一个长时间运行的任务
func task(ctx context.Context, taskID int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Task %d received cancel signal, stopping...\n", taskID)
return
default:
fmt.Printf("Task %d is running...\n", taskID)
time.Sleep(1 * time.Second)
}
}
}
func main() {
// 创建一个可取消的context
ctx, cancel := context.WithCancel(context.Background())
// 启动多个协程执行任务
for i := 1; i <= 3; i++ {
go task(ctx, i)
}
// 模拟5秒后触发取消信号
time.Sleep(5 * time.Second)
fmt.Println("Triggering cancel signal...")
cancel()
// 等待一段时间,确保所有协程都有机会处理取消信号
time.Sleep(2 * time.Second)
}
代码解释
context.WithCancel
: 创建一个可取消的context
,返回一个context.Context
和一个取消函数cancel
。context.Background()
是所有context
的根。task
函数: 每个协程执行的任务。在for
循环中,通过select
语句监听ctx.Done()
通道。当该通道接收到数据时,说明取消信号已触发,协程可以优雅地停止工作。default
分支则表示任务在正常运行,这里简单打印任务运行信息并休眠1秒。- 启动协程: 在
main
函数中,使用go
关键字启动多个协程执行task
函数,并传入相同的ctx
。这样所有协程共享同一个取消信号。 - 触发取消: 模拟5秒后调用
cancel()
函数,这会向所有关联的context
发送取消信号,所有监听ctx.Done()
的协程都会收到信号并停止工作。 - 等待处理: 调用
cancel
后,等待2秒,确保所有协程有足够时间处理取消信号并安全退出。