29
Go语言:调度间隔用哪个好?time.Sleep v.s. time.After
source link: https://www.tuicool.com/articles/BZJzQz7
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
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 语言入门到实战》
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK