Go编程中循环调度任务的执行间隔我们通常采用 time.Sleep或time.After来实现。
写法1:
```
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Cancelled", time.Now())
wg.Done()
return
default:
time.Sleep(time.Second * 10)
fmt.Println("Invoked", time.Now())
}
}
}(ctx)
```
写法2:
```
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Cancelled", time.Now())
wg.Done()
return
case <-time.After(time.Second * 10):
fmt.Println("Invoked", time.Now())
}
}
}(ctx)
```
这两种方式一样吗?那种方式更好呢?
以上两种写法,都可以满足需求。那么是否这两种写法是等效的呢?
当然不是,为了更好的说明它们的差别,请运行下面的这两段测试代码:
```
var wg sync.WaitGroup
func cancelTaskAfter(interval time.Duration, cancel context.CancelFunc) {
go func(cancel context.CancelFunc) {
time.Sleep(interval)
fmt.Println("Cancell task", time.Now())
cancel()
wg.Done()
}(cancel)
}
func TestTimerTask1(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
wg.Add(1)
cancelTaskAfter(time.Second*25, cancel)
wg.Add(1)
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Cancelled", time.Now())
wg.Done()
return
default:
time.Sleep(time.Second * 10)
fmt.Println("Invoked", time.Now())
}
}
}(ctx)
wg.Wait()
}
func TestTimerTask2(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
wg.Add(1)
cancelTaskAfter(time.Second*25, cancel)
wg.Add(1)
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("Cancelled", time.Now())
wg.Done()
return
case <-time.After(time.Second * 10):
fmt.Println("Invoked", time.Now())
}
}
}(ctx)
wg.Wait()
}
```
也许看到这,你大概已经知道这两种写法的不同了。
以下是输出结果
```
=== RUN TestTimerTask1
Invoked 2019-09-22 17:12:07.055392 +0800 CST m=+35.007752073
Invoked 2019-09-22 17:12:17.057073 +0800 CST m=+45.009375450
Cancell task 2019-09-22 17:12:22.051311 +0800 CST m=+50.003583680
Invoked 2019-09-22 17:12:27.060766 +0800 CST m=+55.013010382
Cancelled 2019-09-22 17:12:27.060804 +0800 CST m=+55.013048342
--- PASS: TestTimerTask1 (30.01s)
```
```
=== RUN TestTimerTask2
Invoked 2019-09-22 17:11:42.049262 +0800 CST m=+10.001766181
Invoked 2019-09-22 17:11:52.053054 +0800 CST m=+20.005500478
Cancell task 2019-09-22 17:11:57.050145 +0800 CST m=+25.002563035
Cancelled 2019-09-22 17:11:57.05041 +0800 CST m=+25.002827648
--- PASS: TestTimerTask2 (25.00s)
```
采用Sleep来实现间隔的时候,如果cancel调用后任务协程正好处于sleep过程中,这时任务是无法被及时取消的。
小结
如果你需要任务能够被及时的取消,那你应该采用time.After来控制调用的间隔。
更多知识,欢迎订阅学习 《Go 语言入门到实战》
![IMG_4490.JPG](https://static.studygolang.com/190922/4f8d7857eac23e3f680ab93e640292d3.JPG)
有疑问加站长微信联系(非本文作者))