英文:
timing out with time.After does not behave like timing out with a ticker or a timer
问题
我期望以下两个函数的行为是相同的:
func fillChanTimeoutUsingTicker(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
ticker := time.NewTicker(maxDuration)
for {
select {
case <-ticker.C:
ticker.Stop()
fmt.Println("Ticker: operation timed out")
return c
case c <- "Random message":
default:
fmt.Println("Ticker: chan is full")
return c
}
}
}
func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
for {
select {
case <-time.After(maxDuration):
fmt.Println("time.After: operation timed out")
return c
case c <- "Random message":
default:
fmt.Println("time.After: chan is full")
return c
}
}
}
调用它们的方式是:
resWithTicker := fillChanTimeoutUsingTicker(time.Duration(1*time.Microsecond), 10000000)
fmt.Println(len(resWithTicker))
resWithTimeAfter := fillChanTimeoutUsingTimeAfter(time.Duration(1*time.Microsecond), 10000000)
fmt.Println(len(resWithTimeAfter))
打印结果为:
Ticker: operation timed out
43979
time.After: chan is full
10000000
我原以为它们的行为会完全相同,但实际上它们之间有很大的差异,对此有什么想法吗?
另外,使用计时器(timer)的方式与使用 ticker 的方式一样符合预期。
英文:
I expect the follwoing to functions to behave the same way
func fillChanTimeoutUsingTicker(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
ticker := time.NewTicker(maxDuration)
for {
select {
case <-ticker.C:
ticker.Stop()
fmt.Println("Ticker:operation timedout")
return c
case c <- "Random message":
default:
fmt.Println("Ticker:chan is full")
return c
}
}
}
func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
for {
select {
case <-time.After(maxDuration):
fmt.Println("time.After:operation timedout")
return c
case c <- "Random message":
default:
fmt.Println("time.After:chan is full")
return c
}
}
}
calling them as :
resWithTicker := fillChanTimeoutUsingTicker(time.Duration(1*time.Microsecond), 10000000)
fmt.Println(len(resWithTicker))
resWithTimeAfter := fillChanTimeoutUsingTimeAfter(time.Duration(1*time.Microsecond), 10000000)
fmt.Println(len(resWithTimeAfter))
prints:
Ticker:operation timedout
43979
time.After:chan is full
10000000
i thought that they would behave exactly the same way and i really don't get the huge difference, any thoughts on this?
note also using a timer works as expected like in the ticker function.
答案1
得分: 3
问题出在你的代码中。
在你的第一个示例中,你创建了一个计时器并将其用于超时。在你的第二个示例中,你在每次循环时都创建一个计时器:
case <-time.After(maxDuration):
根据库源代码可以看出,这等同于:
case <- time.NewTimer(maxDuration).C:
如果你在每次循环时都创建一个新的 Ticker/Timer(并且丢弃旧的),它可能永远不会触发。
因此,要使你的第二个示例正确运行,可以按照以下方式编写代码(未经测试):
func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
t := time.After(maxDuration)
for {
select {
case <-t:
fmt.Println("time.After: operation timed out")
return c
case c <- "Random message":
default:
fmt.Println("time.After: chan is full")
return c
}
}
}
英文:
The problem lies within your code.
In your first example, you are creating one ticker and use that for timing out.
In your second example, you create a timer every time you loop:
case <-time.After(maxDuration):
As can be seen in the library sources, this is equivalent to
case <- time.NewTimer(maxDuration).C:
If you create a new Ticker/Timer every time you loop (and discard the old one), it will probably never fire.
So, to get your second example to behave correctly, do it like this (untested):
func fillChanTimeoutUsingTimeAfter(maxDuration time.Duration, chanSize int) chan string {
c := make(chan string, chanSize)
t := time.After(maxDuration)
for {
select {
case <-t:
fmt.Println("time.After:operation timedout")
return c
case c <- "Random message":
default:
fmt.Println("time.After:chan is full")
return c
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论