Golang time包的定時器/斷續器

定時器

在time包中有兩個函數可以幫助我們初始化time.Timer

time.Newtimer函數

初始化一個到期時間據此時的間隔爲3小時30分的定時器

t := time.Newtimer(3*time.Hour + 30*time.Minute)

注意,這裏的變量t是*time.NewTimer類型的,這個指針類型的方法集合包含兩個方法

  • Rest
    • 用於重置定時器
    • 該方法返回一個bool類型的值
  • Stop
    • 用來停止定時器
    • 該方法返回一個bool類型的值,如果返回false,說明該定時器在之前已經到期或者已經被停止了,反之返回true。

通過定時器的字段C,我們可以及時得知定時器到期的這個事件來臨,C是一個chan time.Time類型的緩衝通道,一旦觸及到期時間,定時器就會向自己的C字段發送一個time.Time類型的元素值

示例一:一個簡單定時器

package main

import (
    "fmt"
    "time"
)

func main(){
    //初始化定時器
    t := time.NewTimer(2 * time.Second)
    //當前時間
    now := time.Now()
    fmt.Printf("Now time : %v.\n", now)

    expire := <- t.C
    fmt.Printf("Expiration time: %v.\n", expire)
}

Now time : 2015-10-31 01:19:07.210771347 +0800 CST.
Expiration time: 2015-10-31 01:19:09.215489592 +0800 CST.

示例二:我們在改造下之前的那個簡單超時操作

package main

import (
    "fmt"
    "time"
)
func main(){
    //初始化通道
    ch11 := make(chan int, 1000)
    sign := make(chan byte, 1)

    //給ch11通道寫入數據
    for i := 0; i < 1000; i++ {
        ch11 <- i
    }

    //單獨起一個Goroutine執行select
    go func(){
        var e int
        ok := true
        //首先聲明一個*time.Timer類型的值,然後在相關case之後聲明的匿名函數中儘可能的複用它
        var timer *time.Timer

        for{
            select {
                case e = <- ch11:
                    fmt.Printf("ch11 -> %d\n",e)
                case <- func() <-chan time.Time {
                    if timer == nil{
                        //初始化到期時間據此間隔1ms的定時器
                        timer = time.NewTimer(time.Millisecond)
                    }else {
                        //複用,通過Reset方法重置定時器
                        timer.Reset(time.Millisecond)
                    }
                    //得知定時器到期事件來臨時,返回結果
                    return timer.C
                }():
                    fmt.Println("Timeout.")
                    ok = false
                    break
            }
            //終止for循環
            if !ok {
                sign <- 0
                break
            }
        }

    }()

    //慣用手法,讀取sign通道數據,爲了等待select的Goroutine執行。
    <- sign
}

time.After函數

  • time.After函數, 表示多少時間之後,但是在取出channel內容之前不阻塞,後續程序可以繼續執行
    • 鑑於After特性,其通常用來處理程序超時問題
package main

import (
    "fmt"
    "time"
)

func main(){
    ch1 := make(chan int, 1)
    ch2 := make(chan int, 1)

    select {
        case e1 := <-ch1:
        //如果ch1通道成功讀取數據,則執行該case處理語句
            fmt.Printf("1th case is selected. e1=%v",e1)
        case e2 := <-ch2:
        //如果ch2通道成功讀取數據,則執行該case處理語句
            fmt.Printf("2th case is selected. e2=%v",e2)
        case <- time.After(2 * time.Second):
            fmt.Println("Timed out")
    }
}

Timed out

  • time.Sleep函數,表示休眠多少時間,休眠時處於阻塞狀態,後續程序無法執行.

time.Afterfunc函數

示例三:自定義定時器

package main

import (
    "fmt"
    "time"
)
func main(){
    var t *time.Timer

    f := func(){
        fmt.Printf("Expiration time : %v.\n", time.Now())
        fmt.Printf("C`s len: %d\n", len(t.C))
    }

    t = time.AfterFunc(1*time.Second, f)
    //讓當前Goroutine 睡眠2s,確保大於內容的完整
    //這樣做原因是,time.AfterFunc的調用不會被阻塞。它會以一部的方式在到期事件來臨執行我們自定義函數f。
    time.Sleep(2 * time.Second)
}

Expiration time : 2015-10-31 01:04:42.579988801 +0800 CST.
C`s len: 0

第二行打印內容說明:定時器的字段C並沒有緩衝任何元素值。這也說明了,在給定了自定義函數後,默認的處理方法(向C發送代表絕對到期時間的元素值)就不會被執行了。

斷續器

結構體類型time.Ticker表示了斷續器的靜態結構。
就是週期性的傳達到期時間的裝置。這種裝置的行爲方式與僅有秒針的鐘表有些類似,只不過間隔時間可以不是1s。
初始化一個斷續器

var ticker *timeTicker = time.NewTicker(time.Second)

示例一:使用時間控制停止ticke

package main

import (
    "fmt"
    "time"
)

func main(){
    //初始化斷續器,間隔2s
    var ticker *time.Ticker = time.NewTicker(1 * time.Second)

    go func() {
        for t := range ticker.C {
            fmt.Println("Tick at", t)
        }
    }()

    time.Sleep(time.Second * 5)   //阻塞,則執行次數爲sleep的休眠時間/ticker的時間
    ticker.Stop()     
    fmt.Println("Ticker stopped")
}

Tick at 2015-10-31 01:29:34.41859284 +0800 CST
Tick at 2015-10-31 01:29:35.420131668 +0800 CST
Tick at 2015-10-31 01:29:36.420565647 +0800 CST
Tick at 2015-10-31 01:29:37.421038416 +0800 CST
Tick at 2015-10-31 01:29:38.41944582 +0800 CST
Ticker stopped

示例二:使用channel控制停止ticker

package main

import (
    "fmt"
    "time"
)

func main(){
    //初始化斷續器,間隔2s
    var ticker *time.Ticker = time.NewTicker(100 * time.Millisecond)

    //num爲指定的執行次數
    num := 2
    c := make(chan int, num) 
    go func() {
        for t := range ticker.C {
            c <- 1
            fmt.Println("Tick at", t)
        }
    }()

    time.Sleep(time.Millisecond * 1500)
    ticker.Stop()     
    fmt.Println("Ticker stopped")
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章