我在哪里创建Ticker是否重要?

时间:2016-05-28 04:13:15

标签: go

之间有什么区别吗?
ticker := time.NewTicker(1 * time.Second)

go func() {
    for _ = range ticker.C {
        fmt.Print("Tick")
    }
}()

time.Sleep(3)
ticker.Stop()

var ticker *time.Ticker

go func() {
    ticker = time.NewTicker(1 * time.Second)
    for _ = range ticker.C {
        fmt.Print("Tick")
    }
}()

time.Sleep(3)
ticker.Stop()

就线程安全性而言,尤其是当函数中的工作时间超过刻度的时间时?

我问,因为(当不需要停止Ticker时)后者可以缩短为

go func() {
    for ticker := time.NewTicker(1 * time.Second) ;; <-ticker.C {
        fmt.Print("Tick")
    }
}()
虽然前者不能。这种形式的另一个优点是可以立即触发第一个滴答。

1 个答案:

答案 0 :(得分:2)

代码的第二个版本是错误的:它有竞争条件。

var ticker *time.Ticker

go func() {
    ticker = time.NewTicker(1 * time.Second)
    for _ = range ticker.C {
        fmt.Print("Tick")
    }
}()

time.Sleep(3)
ticker.Stop()

在goroutine内ticker的分配与ticker来电中使用ticker.Stop()之间没有同步。

在实践中,由于长time.Sleep(3),这几乎总是无害的,但是如果可能的话应该避免这种比赛,因为即使它们今天无害,它们也可能在以后引起麻烦。例如,如果代替Sleep你有一些代码需要花费不同的时间,那么如果代码恰好需要很短的时间,你可能会看到nil指针恐慌。

因此,我总是使用代码的第一个版本(在goroutine之外创建ticker的代码)。

代码的第三个版本(其中ticker完全在goroutine中使用)也很好。我绝对会使用这个较短版本的代码,如果可能的话,在goroutine中定义代码。代码的简洁性很好,但我也喜欢外面的代码根本看不到代码,所以代码的读者很容易理解代码的范围。