我使用Ticker定期执行任务,但在更改时遇到了一些问题。我会在收到一些消息后更改自动收报机并更改间隔。以下是重现此问题的示例代码:
package main
import (
"fmt"
"time"
)
type A struct {
ticker *time.Ticker
}
func (a *A) modify() {
a.ticker.Stop()
a.ticker = time.NewTicker(time.Second)
}
func main() {
a := new(A)
a.ticker = time.NewTicker(time.Second)
go func() {
for {
select {
case <-a.ticker.C:
fmt.Println("now")
go a.modify()
/*
default:
//fmt.Println("default")
time.Sleep(time.Millisecond * 100)
*/
}
}
}()
time.Sleep(time.Second * 60)
}
“now”将仅打印一次。但如果我删除“go”,它会不断打印出来,如下所示:
package main
import (
"fmt"
"time"
)
type A struct {
ticker *time.Ticker
}
func (a *A) modify() {
a.ticker.Stop()
a.ticker = time.NewTicker(time.Second)
}
func main() {
a := new(A)
a.ticker = time.NewTicker(time.Second)
go func() {
for {
select {
case <-a.ticker.C:
fmt.Println("now")
a.modify()
/*
default:
//fmt.Println("default")
time.Sleep(time.Millisecond * 100)
*/
}
}
}()
time.Sleep(time.Second * 60)
}
另外,如果我将默认子句保留为未注释,则可以连续打印“now”。 任何人都可以解释这会发生什么?
答案 0 :(得分:0)
问题是goroutine是异步运行的。
使用a.modify()
时,您的代码的行为与此类似:
a.ticker.C
a.ticker.C
a.ticker.C
select
醇>
在这种情况下,2中新创建的a.ticker.C
与3中的等待频道相同。
如果你在goroutine中做2.它可以按照以下顺序完成
a.ticker.C
a.ticker.C
select
a.ticker.C
在这种情况下,在2.中等待的频道与在3中新创建的频道不同。 由于选择频道是旧的停止,它永远不会得到任何勾号。
您可以确认此行为,插入一些fmt.Printf
并注意a.ticker.C
的地址。
func (a *A) modify() {
a.ticker.Stop()
fmt.Printf("ticker stopped: %p\n", &a.ticker.C)
a.ticker = time.NewTicker(time.Second)
fmt.Printf("new ticker created: %p\n", &a.ticker.C)
}
func main() {
a := new(A)
a.ticker = time.NewTicker(time.Second)
go func() {
for {
fmt.Printf("waiting for ticker: %p\n", &a.ticker.C)
select {
....
a.modify()
:
waiting for ticker: 0xc420010100
ticker stopped: 0xc420010100
new ticker created: 0xc420068000
waiting for ticker: 0xc420068000
ticker stopped: 0xc420068000
new ticker created: 0xc420068080
waiting for ticker: 0xc420068080
go a.modify()
:
waiting for ticker: 0xc420010100
waiting for ticker: 0xc420010100
ticker stopped: 0xc420010100
new ticker created: 0xc420066040
你可以看到go a.modify()
,你不是在等待新创建的频道。
默认行为的更新:
将default:
与go a.modify()
一起使用时,其行为将如此。
a.ticker.C
,打勾,打电话给go a.modify()
做3。a.ticker.C
,什么都没有,所以回退到默认值并睡眠100毫秒。a.ticker.C
a.ticker.C
,什么都没有,所以回退到默认值并睡眠100毫秒。a.ticker.C
,什么都没有,所以回退到默认值并睡眠100毫秒。a.ticker.C
,什么都没有,所以回退到默认值并睡眠100毫秒。.....
a.ticker.C
,打勾,致电go a.modify()
关键是即使for{}
没有任何内容,a.ticker.C
循环也可以继续运行。
您可以使用相同的代码确认行为。
waiting ticker: 0xc420010100 <-- 1.
now <-- 1.
waiting ticker: 0xc420010100 <-- 2.
default <-- 2.
ticker stopped: 0xc420010100 <-- 3.
new ticker created: 0xc420066240 <-- 3.
waiting ticker: 0xc420066240 <-- 4.
default <-- 4.