ティッカーチャネルにまたがって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
そのため、ゴルーチンは決して存在しません。このケースを処理するためのより良い方法はありますか?ゴルーチンが決して終了しないことを気にする必要がありますか?
2番目のチャネルで「完了」を通知し、ゴルーチンでティッカーと完了チャネルのどちらかを選択します。
本当にやりたいことによっては、より良い解決策が存在するかもしれませんが、これは削減されたデモコードからはわかりません。
Volkerが提案したように2番目のチャネルを使用しました。これは私が実行することになったものです:
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)
}
あなたはこのようにすることができます。
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)
}
より多くのスペースを節約する必要がある場合は、空の構造体のチャネルを使用してください-メモリを消費しないstruct {}。そして、上記のように、その中に何かを送信しないでください-ちょうど閉じるだけで、実際にはゼロ値を送信します。