2017-10-16 58 views
0
package main 
import "fmt" 
import "time" 

func main() { 
    ticker := time.NewTicker(time.Millisecond * 500) 
    go func() { 
     for t := range ticker.C { 
      fmt.Println("Tick at", t) 
     } 
     fmt.Println("ticker stopped") 
    }() 
    time.Sleep(time.Second * 5) 
    ticker.Stop() 
    time.Sleep(time.Second * 5) 
} 

我以爲當我打電話給ticker.Stop()時,ticker.C應該告訴goroutine它已經結束,所以for循環應該結束,但它看起來不像那樣,字符串「ticker stopped」從不打印。股票代碼告訴goroutine它是通過它的ticker.C停止的嗎?

+2

從文檔:'停止不關閉channel' – JimB

回答

1

正如JimB指出的那樣,time.Ticker指定Stop()不會關閉頻道,to prevent a read from the channel succeeding incorrectly.您最好的選擇可能是退出頻道。

package main 

import "fmt" 
import "time" 

func main() { 
    ticker := time.NewTicker(time.Millisecond * 500) 
    quit := make(chan struct{}) 
    go func() { 
     for { 
      select { 
      case t := <-ticker.C: 
       fmt.Println("Tick at", t) 
      case <-quit: 
       fmt.Println("ticker stopped") 
       return 
      } 
     } 
    }() 
    time.Sleep(time.Second * 5) 
    ticker.Stop() 
    close(quit) 
    time.Sleep(time.Second * 5) 
} 

https://play.golang.org/p/xTKNkMtdIf

+0

很抱歉,但我不明白爲什麼停不關閉通道的原因。我知道你已經解釋了這一點 - 「防止通道讀取錯誤」,但仍然讓我感到困惑。 –

+0

@luckyyang過去這個API的設計怪癖已經出現,看起來是一個實現問題。有關更多詳細信息,請參閱https://codereview.appspot.com/5491059。 – jmaloney

+0

所以,假設你在某個地方做了一個'<-ticker.C',而不是在'for range'循環中做。在這種情況下,關閉頻道將觸發該接收,就像發送的實際值一樣(因爲從閉合頻道接收即時成功)。所以它並沒有關閉頻道,所以接收者無法仔細考慮這是一個問題。 – Kaedys