目 录CONTENT

文章目录

Go并发编程-定时器和断续器

Sakura
2023-09-20 / 1 评论 / 1 点赞 / 24 阅读 / 6517 字 / 正在检测是否收录...

一: 基本介绍

Timer&Ticker是 Go 标准包 time 中定义的类型,通过 Channel 与程序进行通信

// 定时器
time.Timer
// 断续器
time.Ticker
  • 定时器Timer类似于一次性闹钟

  • 断续器Ticker类似于重复性闹钟,也成循环定时器

应用场景 : 定时任务 , 程序每隔多长时间执行一次 , 程序某个时间点开始结束

二: 定时器

  • 使用语法

// time.NewTimer
func NewTimer(d Duration) *Timer

创建定时器 , 参数是 Duration 时间。返回为 *Timer*Timer.C是用来接收到期通知的单向 Channel

type Timer struct {
    C <-chan Time
}

只要能从*Timer.c上接收数据 , 就意味着定时器到时了 , 接收到的元素是time.Time 类型的数据 , 为到时时间

1. 定时器典型使用

func TimerAA() {
	// 创建定时器
	t := time.NewTimer(2 * time.Second)
	fmt.Println("定时器开始计时:", time.Now().String())

	end := <-t.C
	fmt.Println("定时器定时结束:", end.String())
}

2. 定时器停止和重置

// 停止计时器
// 返回值bool类型,返回false,表示该定时器早已经停止,返回true表示由本次调用停止
func (t *Timer) Stop() bool

// 重置定时器
// 返回值bool类型,返回false,表示该定时器早已经停止,返回true表示由本次调用重置
func (t *Timer) Reset(d Duration) bool

注意:

停止和重置是定时器没有结束的时候才能调用的

一旦能从time.C 中拿到内容说明定时器以及结束了 , 此时调用StopReset没有意义

  • 猜数组游戏 , 一共猜五次 , 每次 3 秒

func TimerStop() {
	// 初始化数组
	ch := make(chan int)

	// 每隔0.4秒猜一次
	go func() {
		for {
			ch <- rand.Intn(10)
			time.Sleep(400 * time.Millisecond)
		}
	}()

	// 每一局时间
	t := time.NewTimer(3 * time.Second)
	// 统计猜中次数和未猜中次数
	GuessYes, GuessNo := 0, 0
	// 五轮猜数字游戏
	for i := 0; i < 5; i++ {
	Guess:
		for {
			select {
			case value := <-ch:
				fmt.Println("猜的数字为: ", value)
				if value == 5 {
					fmt.Println("猜中了数字")
					GuessYes++
					// 重置定时器,开始下一轮游戏
					t.Reset(time.Second * 3)
					break Guess
				}
			case <-t.C:
				fmt.Println("时间结束,没有猜中数字")
				GuessNo++
				// 重新创建定时器
				t = time.NewTimer(3 * time.Second)
				break Guess
			}

		}
	}
	fmt.Println("游戏结束,猜中次数为: ", GuessYes, "失败次数为", GuessNo)
}

3. 不需要定时器的关闭和重置

func After(d Duration) <-chan Time
  • 返回值是定时器到期的通知 Channel , 不需要从 t.c 中取数据

func TimerChannel() {
	ch := time.After(5 * time.Second)
	fmt.Println("设置定时器: ", time.Now().String())

	now := <-ch
	fmt.Println("定时器结束: ", now.String())
}

4. 定时器结束执行特定函数

func AfterFunc(d Duration, f func()) *Timer

三: 断续器 ( 循环定时器 )

func NewTicker(d Duration) *Ticker
  • 创建断续器。参数是Duration时间。返回为 *Ticker*Ticker.C是用来接收到期通知的单向 Channel

type Ticker struct {
    C <-chan Time // The channel on which the ticks are delivered.
}
  • 因此我们只要可从 *Ticker.C上接收数据,就意味着断续器时间到。接收到的元素是 time.Time 类型数据,为到时时间。当接收到到期时间后,间隔下一个Duration还会再次接收到到期时间。

// Ticket 方法
// 停止断续器
func (t *Ticker) Stop()
// 重置断续器间隔时间
func (t *Ticker) Reset(d Duration)
  • 模拟定期心跳检测的案例

func TickerHeart() {
	// 断续器,每隔两秒做一次心跳检测
	ticker := time.NewTicker(2 * time.Second)

	// 定时器,表示只执行五次10秒的心跳检测
	// 不用定时器就是一直执行每隔两秒的心跳检测
	timer := time.NewTimer(10 * time.Second)

	loop:
	for now := range ticker.C {
		// 心跳检测
		fmt.Println("心跳检测 , http://domain/ping , ", now.String())

		// 非阻塞读ticker
		select {
		case <-timer.C:
			ticker.Stop()
			fmt.Println("心跳检测结束")
			break loop
		default:
			// 无阻塞的接收操作
		}
	}
}

1

评论区