time.Timer time.NewTicker time.After 区别和使用注意事项

首先time.Timer和 time.NewTicker属于定时器,二者的区别在于

timer : 到固定时间后会执行一次,请注意是一次,而不是多次。但是可以通过reset来实现每隔固定时间段执行

ticker : 每隔固定时间都会触发,多次执行.  具体请查看下面示例1

time.After : 用于实时超时控制,常见主要和select  channel结合使用.查看代码示例2

//示例1
package main

import (
	"fmt"
	"sync"
	"time"
)

// timer 和 ticker 区别
// timer  是到固定时间后会执行一次
// ticker 每隔固定时间都会触发  常用的一种定时器
func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	timer := time.NewTimer(time.Second * 3)
	go func(t *time.Timer) {
		defer wg.Done()
		for {
			<-t.C
			fmt.Println("timer", time.Now().Format("2006-01-02 15:04:05"))
       //利用Reset可以实现timer每隔固定时间段触发。reset 重新开始计时,如果调用时 t 还在等待中会返回真;如果 t已经到期或者被停止了会返回假。可自行打印查看结果
            // t.Reset(2 * time.Second)
			//expire := t.Reset(2 * time.Second)
			//fmt.Println("expire:",expire)
		
		}
	}(timer)


	ticker := time.NewTicker(time.Second * 4)
	go func(t *time.Ticker) {
		defer wg.Done()
		for {
			<-t.C
			fmt.Println("ticker", time.Now().Format("2006-01-02 15:04:05"))
		}
	}(ticker)

	wg.Wait()

}


//timer未使用reset的执行结果如下:
/*
timer 2021-01-05 15:06:34
ticker 2021-01-05 15:06:35
ticker 2021-01-05 15:06:39
ticker 2021-01-05 15:06:43
....
....
....
*/
// timer使用reset的执行结果如下:
/*
timer 2021-01-05 15:19:08
ticker 2021-01-05 15:19:09
timer 2021-01-05 15:19:10
timer 2021-01-05 15:19:12
ticker 2021-01-05 15:19:13
timer 2021-01-05 15:19:14
timer 2021-01-05 15:19:16
...
...
...
*/
// 示例2
package main

import (
    "time"
    "fmt"
)

func main() {
    ch := make(chan string)

    go func() {
        time.Sleep(time.Second * 2)

        ch <- "result"
    }()

    select {
    case res := <-ch:
        fmt.Println(res)
    case <-time.After(time.Second * 1):
        fmt.Println("timeout")
    }
}

再知道二者的区别之后,是否发现了上面有缺陷。没有关闭定时器的执行。定时器未关闭!!!!大家会想到stop ,使用stop注意是在协程内还是携程外,以及使用的场景业务

协程退出时需要关闭,避免资源l浪费,使用defer ticker.Stop() 

package main

import (
	"fmt"
	"time"
)

//定时器的stop
func main() {

	// 协程内的定时器 stop  在协程结束时,关闭默认资源定时器,channel 具体根据业务来看
	go func() {
		ticker := time.NewTicker(5 * time.Second)
		// 此处 可以简化为defer ticker.Stop()
		defer func() {
			fmt.Println("stop")
			ticker.Stop()
		}()
	
	   select {
	   case <- ticker.C:
			fmt.Println("ticker..." )
		}
	}()

	// 停止ticker
	stopChan := make(chan bool)
	ticker := time.NewTicker(5 * time.Second)
	go func(ticker *time.Ticker) {
		defer func() {
			ticker.Stop()
			fmt.Println("Ticker2 stop")
		}()
		for {
			select {
			case s := <-ticker.C:
				fmt.Println("Ticker2....",s)
			case stop := <-stopChan:
				if stop {
					fmt.Println("Stop")
					return
				}
			}
		}

	}(ticker)
	// 此处的stop 并不会结束上面协程,也不会打印出 Ticker2 stop  只能借助stopChan,让协程结束时关闭ticker或者协程出现panic时执行defer
	//ticker.Stop()
	stopChan <- true
	close(stopChan)
	
	time.Sleep(time.Second * 10)
	fmt.Println("main end")
	
}

实际使用场景的代码示例

package main

import (
	"fmt"
	"time"
)

// 每秒钟调⽤⼀次 proc 并保证程序不退 出
func main() {
	go func() {
		t := time.NewTicker(time.Second * 1)
		defer func() {
			t.Stop()
		}()
		// 1 在这⾥需要你写算法
		// 2 要求每秒钟调⽤⼀次proc函数
		// 3 要求程序不能退出
		for {
			select {
			case <-t.C:
				go func() {
					defer func() {
						if err := recover(); err != nil {
							fmt.Println(err)
						}
					}()
					proc()
				}()
			}
		}

		// timer执行
		//for {
		//	// 1.当前时间
		//	now := time.Now()
		//	// 1.间隔1秒时长
		//	next := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()+1, 0, now.Location())
		//	t := time.NewTimer(next.Sub(now))
		//	//
		//	go func() {
		//		defer func() {
		//			if err := recover(); err != nil {
		//				fmt.Println(err)
		//			}
		//		}()
		//		proc()
		//	}()
		//	<- t.C
		//}

		}()
	select {

	}

}

func proc() {
	panic("ok")
}

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值