可取消任务
难度:⭐⭐ 中等
考点
- context.WithCancel 取消传播
- 任务中断与清理
- 心跳模式
提示
- LongTask 每步用 select 检查 ctx.Done()
- TaskWithCleanup 用 defer 确保 cleanup 执行
- Heartbeat 后台 goroutine + ticker + select ctx.Done()
参考答案(Go)
点击展开参考答案
go
//go:build ignore
package answer
import (
"context"
"time"
)
func LongTask(ctx context.Context, steps int, stepDuration time.Duration) (int, error) {
for i := 0; i < steps; i++ {
select {
case <-ctx.Done():
return i, ctx.Err()
case <-time.After(stepDuration):
}
}
return steps, nil
}
func TaskWithCleanup(ctx context.Context, work func(ctx context.Context) error, cleanup func()) error {
defer cleanup()
return work(ctx)
}
func Heartbeat(ctx context.Context, interval time.Duration) <-chan time.Time {
ch := make(chan time.Time)
go func() {
defer close(ch)
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
select {
case ch <- t:
case <-ctx.Done():
return
}
case <-ctx.Done():
return
}
}
}()
return ch
}