如果我超过了一个自动收报机通道并且调用了stop(),则该通道已停止但未关闭。
在此示例中:
package main
import (
"time"
"log"
)
func main() {
ticker := time.NewTicker(1 * time.Second)
go func(){
for _ = range ticker.C {
log.Println("tick")
}
log.Println("stopped")
}()
time.Sleep(3 * time.Second)
log.Println("stopping ticker")
ticker.Stop()
time.Sleep(3 * time.Second)
}
跑步产生:
2013/07/22 14:26:53 tick
2013/07/22 14:26:54 tick
2013/07/22 14:26:55 tick
2013/07/22 14:26:55 stopping ticker
所以goroutine永远不会退出。有没有更好的方法来处理这种情况?我应该关心goroutine从未退出吗?
答案 0 :(得分:12)
Volker建议使用第二个频道。这就是我最终运行的:
package main
import (
"log"
"time"
)
// Run the function every tick
// Return false from the func to stop the ticker
func Every(duration time.Duration, work func(time.Time) bool) chan bool {
ticker := time.NewTicker(duration)
stop := make(chan bool, 1)
go func() {
defer log.Println("ticker stopped")
for {
select {
case time := <-ticker.C:
if !work(time) {
stop <- true
}
case <-stop:
return
}
}
}()
return stop
}
func main() {
stop := Every(1*time.Second, func(time.Time) bool {
log.Println("tick")
return true
})
time.Sleep(3 * time.Second)
log.Println("stopping ticker")
stop <- true
time.Sleep(3 * time.Second)
}
答案 1 :(得分:10)
在第二个频道上发出“完成”信号,然后在你的goroutine中选择自动收报机和完成频道。
根据您真正想要做的事情,可能存在更好的解决方案,但这很难从简化的演示代码中看出来。
答案 2 :(得分:1)
package main
import (
"fmt"
"time"
)
func startTicker(f func()) chan bool {
done := make(chan bool, 1)
go func() {
ticker := time.NewTicker(time.Second * 1)
defer ticker.Stop()
for {
select {
case <-ticker.C:
f()
case <-done:
fmt.Println("done")
return
}
}
}()
return done
}
func main() {
done := startTicker(func() {
fmt.Println("tick...")
})
time.Sleep(5 * time.Second)
close(done)
time.Sleep(5 * time.Second)
}
答案 3 :(得分:0)
如果需要节省更多空间,请使用空结构的通道 - struct {},它不需要内存。并且如上所述,不要发送内容 - 只需关闭,实际上发送零值。