GO: 定时器NewTimer、NewTicker 和time.After

1、定时器(time.NewTimer)

Go语言的定时器实质是单向通道,time.Timer结构体类型中有一个time.Time类型的单向chan,源码(src/time/time.go)如下

type Timer struct {
    C <-chan Time
    r runtimeTimer
}

初始化 Timer 方法为NewTimer
示例

package main

import (
	"fmt"

	"time"
)

func main() {

	t := time.NewTimer(time.Second * 2)
	defer t.Stop()
	for {
		<-t.C
		fmt.Println("timer running...")
		// 需要重置Reset 使 t 重新开始计时
		t.Reset(time.Second * 2)
	}
}

输出
timer running…
timer running…
timer running…
timer running…
这里使用NewTimer定时器需要t.Reset重置计数时间才能接着执行。如果注释 t.Reset(time.Second * 2)会导致通道堵塞,报fatal error: all goroutines are asleep - deadlock!错误。
同时需要注意 defer t.Stop()在这里并不会停止定时器。这是因为Stop会停止Timer,停止后,Timer不会再被发送,但是Stop不会关闭通道,防止读取通道发生错误。
如果想停止定时器,只能让go程序自动结束。
示例
package main

import (
“fmt”
“time”
)

func main() {

t := time.NewTimer(time.Second * 2)

ch := make(chan bool)
go func(t *time.Timer) {
	defer t.Stop()
	for {
		select {
		case <-t.C:
			fmt.Println("timer running....")
			// 需要重置Reset 使 t 重新开始计时
			t.Reset(time.Second * 2)
		case stop := <-ch:
			if stop {
				fmt.Println("timer Stop")
				return
			}
		}
	}
}(t)
time.Sleep(10 * time.Second)
ch <- true
close(ch)
time.Sleep(1 * time.Second)

2、定时期(NewTicker)

package main

import (
	"fmt"
	"time"
)

func main() {
		t := time.NewTicker(time.Second*2)
		defer t.Stop()
		for {
			<- t.C
			fmt.Println("Ticker running...")
		}		
}

结果
Ticker running…
Ticker running…
Ticker running…
ticker只要定义完成后,不需要其他操作就可以定时执行。
这里的defer t.Stop()和上面示例相似,也不会停止定时器,解决办法一样。

package main

import (
	"time"
	"fmt"
)

func main() {

	ticker := time.NewTicker(2 * time.Second)
	ch := make(chan bool)
	go func(ticker *time.Ticker) {
		defer ticker.Stop()
		for {
			select {
			case <-ticker.C:
				fmt.Println("Ticker running...")
			case stop := <-ch:
				if stop {
					fmt.Println("Ticker Stop")
					return
				}
			}
		}
	}(ticker)
	time.Sleep(10 * time.Second)
	ch <- true
	close(ch)
}

3、time.After

time.After()表示多长时间长的时候后返回一条time.Time类型的通道消息。但是在取出channel内容之前不阻塞,后续程序可以继续执行。

先看源码(src/time/sleep.go)

func After(d Duration) <-chan Time {
   return NewTimer(d).C
}

通过源码我们发现它返回的是一个NewTimer(d).C,其底层是用NewTimer实现的,所以如果考虑到效率低,可以直接自己调用NewTimer。

示例1

package main

import (
   "fmt"
   "time"
)

func main() {
   t := time.After(time.Second * 3)
   fmt.Printf("t type=%T\n", t)
   //阻塞3秒
   fmt.Println("t=", <-t)
}

运行结果

t type=<-chan time.Time
t= 2019-05-23 09:58:59.5103274 +0800 CST m=+3.008172101

先打印第一行,3s后打印第二行

基于time.After()特性可以配合select实现计时器

示例2

package main

import (
   "fmt"
   "time"
)

func main() {
   ch1 := make(chan int, 1)
   ch1 <- 1
   for {
      select {
      case e1 := <-ch1:
         //如果ch1通道成功读取数据,则执行该case处理语句
         fmt.Printf("1th case is selected. e1=%v\n", e1)
      case <-time.After(time.Second*2):
         fmt.Println("Timed out")
      }
   }

}

1th case is selected. e1=1
Timed out
Timed out
Timed out
Timed out

select语句阻塞等待最先返回数据的channel`,如ch1通道成功读取数据,则先输出1th case is selected. e1=1,之后每隔2s输出 Timed out。

相关推荐

  1. go】延迟执行定时器实现

    2024-05-16 03:36:04       34 阅读
  2. GO: 定时器NewTimer、NewTicker time.After

    2024-05-16 03:36:04       11 阅读
  3. [云原生] Go 定时器

    2024-05-16 03:36:04       32 阅读
  4. uniapp 使用定时器取消定时器

    2024-05-16 03:36:04       19 阅读
  5. uniApp设置清除定时器

    2024-05-16 03:36:04       19 阅读
  6. uni-app 中使用定时器取消定时器

    2024-05-16 03:36:04       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-16 03:36:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-16 03:36:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-16 03:36:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-16 03:36:04       18 阅读

热门阅读

  1. C++优缺点 zty出品

    2024-05-16 03:36:04       10 阅读
  2. 远程桌面局域网 工具

    2024-05-16 03:36:04       11 阅读
  3. TypeScript 学习笔记

    2024-05-16 03:36:04       9 阅读
  4. VO、DTO、DO、PO 详解 + 举例说明

    2024-05-16 03:36:04       10 阅读
  5. Python 无法联网环境如何安装python包

    2024-05-16 03:36:04       9 阅读
  6. 软件工程课程设计之酒店管理系统的设计与实现

    2024-05-16 03:36:04       11 阅读
  7. MATLAB概述

    2024-05-16 03:36:04       12 阅读
  8. 渗透相关面试+流量分析

    2024-05-16 03:36:04       8 阅读