2017-10-16 55 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