我有一个永远循环,它有一个 Timer 变量,在一段时间后执行一个函数。
package main
import (
fmt "fmt"
"time"
)
func exe() {
fmt.Println("10-seconds-of-time-is-done")
}
func t() {
var timerCheck *time.Timer
fmt.Println("here's the timerCheck", timerCheck)
for {
timerCheck = time.AfterFunc(10*time.Second, func() { exe() })
fmt.Println("exiting-from-function-t")
return
}
}
func main() {
t()
fmt.Println("waiting-inside-main")
time.Sleep(20 * time.Second)
}
这是输出。我不明白函数
t()
立即返回,但 timerCheck
在 10 秒后执行其 exe()
函数。
here's the timerCheck <nil>
exiting-from-function-t
waiting-inside-main
10-seconds-of-time-is-done
这怎么可能?在标准库中,关于
AfterFunc
的说法如下
// AfterFunc waits for the duration to elapse and then calls f
// in its own goroutine. It returns a Timer that can
// be used to cancel the call using its Stop method.
func AfterFunc(d Duration, f func()) *Timer {
t := &Timer{
r: runtimeTimer{
when: when(d),
f: goFunc,
arg: f,
},
}
startTimer(&t.r)
return t
}
我希望所有与timerCheck`相关的东西都应该被释放,因为外部函数的工作已经完成,基本上这个函数的堆栈被释放了(我猜:/)。
为了检查堆栈/堆分配,输出如下;
./main.go:9:13: ... argument does not escape
./main.go:9:14: "10-seconds-of-time-is-done" escapes to heap
./main.go:14:13: ... argument does not escape
./main.go:14:14: "here's the timerCheck" escapes to heap
./main.go:16:47: func literal escapes to heap
./main.go:17:14: ... argument does not escape
./main.go:17:15: "exiting-from-function-t" escapes to heap
./main.go:24:13: ... argument does not escape
./main.go:24:14: "waiting-inside-main" escapes to heap
func literal escapes to heap
是不是因为这个,所以exe
功能还在运行?
我需要一些关于
timerCheck
和 exe()
功能如何在 10 秒后仍然有效的内部指导?即使函数 t()
立即返回。没想到会打印出这个日志10-seconds-of-time-is-done
。因为功能t()
已经完成了。
示例代码是可执行的,可以尝试。
即使函数声明它返回,定时器变量仍然存在,因为定时器创建了一个引用它的 goroutine。 goroutine 等待给定的持续时间,发送信号或调用 AfterFunc,然后终止。只有在此之后,计时器变量才能被垃圾收集。 AfterFunc 异步执行。