Go語言中定時器的使用


GO語言在time包中提供了三種定時器的使用方式:

1.第一種:ticker

 

// A Ticker holds a channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
	C <-chan Time // The channel on which the ticks are delivered.
	r runtimeTimer
}

 

 通過 time.NewTicker() 創建,這種類型,ticker會不斷的按照設定的間隔時間觸發,除非主動終止運行。

2.第二種:timer

 

// The Timer type represents a single event.
// When the Timer expires, the current time will be sent on C,
// unless the Timer was created by AfterFunc.
// A Timer must be created with NewTimer or AfterFunc.
type Timer struct {
	C <-chan Time
	r runtimeTimer
}

 

 通過 time.NewTimer() 創建,這種類型,timer只會執行一次,當然,可以在執行完以后通過調用 timer.Reset() 讓定時器再次工作,並可以更改時間間隔。

3.第三種:After()

 

// After waits for the duration to elapse and then sends the current time
// on the returned channel.
// It is equivalent to NewTimer(d).C.
// The underlying Timer is not recovered by the garbage collector
// until the timer fires. If efficiency is a concern, use NewTimer
// instead and call Timer.Stop if the timer is no longer needed.
func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

 

 從代碼可以看到,After()其實是Timer的一個語法糖。


 

下面通過代碼演示一下三種方式的使用:

1.Ticker

 1     ticker := time.NewTicker(time.Second * 1) // 運行時長
 2     ch := make(chan int)
 3     go func() {
 4         var x int
 5         for x < 10 {
 6             select {
 7             case <-ticker.C:
 8                 x++
 9                 fmt.Printf("%d\n", x)
10             }
11         }
12         ticker.Stop()
13         ch <- 0
14     }()
15     <-ch                                    // 通過通道阻塞,讓任務可以執行完指定的次數。

該ticker每1秒觸發一次,即ticker.C中每一秒會有一個內容加入,最后通過向ch中寫入數字,讓程序解除阻塞,繼續執行。

2.Timer

 1     timer := time.NewTimer(time.Second * 1) // timer 只能按時觸發一次,可通過Reset()重置后繼續觸發。
 2     go func() {
 3         var x int
 4         for {
 5             select {
 6             case <-timer.C:
 7                 x++
 8                 fmt.Printf("%d,%s\n", x, time.Now().Format("2006-01-02 15:04:05"))
 9                 if x < 10 {
10                     timer.Reset(time.Second * 2)
11                 } else {
12                     ch <- x
13                 }
14             }
15         }
16     }()
17     <-ch

3.After()

 1     // 阻塞一下,等待主進程結束
 2     tt := time.NewTimer(time.Second * 10)
 3     <-tt.C
 4     fmt.Println("over.")
 5 
 6     <-time.After(time.Second * 4)
 7     fmt.Println("再等待4秒退出。tt 沒有終止,打印出 over 后會看見在繼續執行...")
 8     tt.Stop()
 9     <-time.After(time.Second * 2)
10     fmt.Println("tt.Stop()后, tt 仍繼續執行,只是關閉了 tt.C 通道。")

4.我們可以利用這些基本的方法,設計自己的定時任務管理。

 1 type jobFunc2 func(j *job)
 2 
 3 type job struct {
 4     jf     jobFunc2
 5     params map[string]interface{}
 6     ch     chan int
 7 }
 8 
 9 func NewJob() *job {
10     return &job{
11         params: make(map[string]interface{}),
12         ch:     make(chan int),
13     }
14 }
15 
16 func (j *job) Run(t time.Duration) {
17     ticker := time.NewTicker(time.Second * t)
18     go func() {
19         for {
20             select {
21             case <-ticker.C:
22                 j.jf(j)
23             case <-j.ch:
24                 fmt.Println("收到結束指令")
25                 ticker.Stop()
26                 break
27             }
28         }
29     }()
30     
31 }
32 
33 func main() {
34     j := NewJob()
35     j.jf = func(jj *job) {
36         fmt.Println("定時任務執行...", time.Now().Format("15:04:05 2006-02-01"), jj.params)
37     }
38     j.params["p1"] = "第一個參數"
39     j.params["p2"] = 100
40     j.Run(1)
41 
42     // 阻塞一下,等待主進程結束
43     tt := time.NewTimer(time.Second * 10)
44     <-tt.C
45     fmt.Println("over.")
46 
47     <-time.After(time.Second * 4)
48     fmt.Println("再等待4秒退出。tt 沒有終止,打印出 over 后會看見在繼續執行...")
49     tt.Stop()
50     <-time.After(time.Second * 2)
51     fmt.Println("tt.Stop()后, tt 仍繼續執行,只是關閉了 tt.C 通道。")
52 }

 

部分執行結果截圖:

 

最后補充一下,通過channel去終止任務的執行。

 1     // 阻塞一下,等待主進程結束
 2     tt := time.NewTimer(time.Second * 10)
 3     <-tt.C
 4     fmt.Println("over.")
 5 
 6     <-time.After(time.Second * 4)
 7     fmt.Println("再等待4秒退出。tt 沒有終止,打印出 over 后會看見在繼續執行...")
 8     tt.Stop()
 9     <-time.After(time.Second * 2)
10     fmt.Println("tt.Stop()后, tt 仍繼續執行,只是關閉了 tt.C 通道。")
11     j.ch <- 0
12     <-time.After(time.Second * 2)
13     fmt.Println("又等了2秒鍾...這兩秒鍾可以看到 tt 沒干活了...")

 

 

 

 

在GO語言編寫中,要熟練使用 channel

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM