Go AfterFunc 不触发

前言

函数原型为:

func AfterFunc(d Duration, f func()) *Timer

Go 的 time.AfterFunc 的作用是等待指定的时间间隔,然后在它自己的 goroutine 中调用 f

现在有一个问题,我明明调用了 AfterFunc,但是它还没调用我指定的函数,程序就退出了。程序如下所示:

package main

import (
	"fmt"
	"time"
)

func main() {
	time.AfterFunc(5*time.Second, func() {
		fmt.Println("5s passed")
	})
}

这段代码什么都没打印就结束了。

问题解决

上面的问题看起来像是 main goroutine 退出了,程序直接退出,还没来得及调用我们指定的函数。

下面就通过源码来看看是不是我们猜测的这样,AfterFunc 的源码如下:

func AfterFunc(d Duration, f func()) *Timer {
	t := &Timer{
		r: runtimeTimer{
			when: when(d),
			f:    goFunc,
			arg:  f,
		},
	}
	startTimer(&t.r)
	return t
}

上面的代码很简单,先构造一个定时器,然后启动定时器。定时器的内容也很好理解,在 when: when(d) 时间,调用 f: goFunc 函数,函数的参数是 arg: f。

when(d) 的值是什么呢?

func when(d Duration) int64 {
	if d <= 0 {
		return runtimeNano()
	}
	t := runtimeNano() + int64(d)
	if t < 0 {
		t = 1<<63 - 1 // math.MaxInt64
	}
	return t
}

可以看到 when 就是当前时间,再加上我们指定的时间间隔。

那 goFunc 又是什么呢?

func goFunc(arg any, seq uintptr) {
	go arg.(func())()
}

这个函数的作用就是创建一个 goroutine,在 goroutine 内运行 arg 函数。

arg 就是我们传给 AfterFunc 要运行的函数,先使用类型断言将其转换成函数,然后再运行它。

于是,问题就解决了,就是因为 main goroutine 先退出了,导致程序直接退出,还没来得及执行我们指定的打印函数。下面给出两种解决方案:

使用 select 替换 AfterFunc:

func main() {
	select {
	case <-time.After(5 * time.Second):
		func() {
			fmt.Println("5s passed")
		}()
	}
}

使用 WaitGroup 等待其他 goroutine 结束:

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	
	time.AfterFunc(5*time.Second, func() {
		defer wg.Done()
		fmt.Println("5s passed")
	})

	wg.Wait()
}

参考资料

相关推荐

  1. Go AfterFunc 触发

    2024-06-13 21:46:02       7 阅读
  2. FPGA中为什么能双时钟触发

    2024-06-13 21:46:02       36 阅读
  3. QT笔记 - QToolButton triggered(QAction *)触发问题

    2024-06-13 21:46:02       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-13 21:46:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-13 21:46:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-13 21:46:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-13 21:46:02       20 阅读

热门阅读

  1. 源码编译构建LAMP

    2024-06-13 21:46:02       8 阅读
  2. 超详细Python教程——迭代器和生成器综合例子

    2024-06-13 21:46:02       9 阅读
  3. C 运算符优先级

    2024-06-13 21:46:02       9 阅读
  4. windows执行定时任务

    2024-06-13 21:46:02       8 阅读
  5. 使用Kube-Bench对Kubernetes进行安全检测

    2024-06-13 21:46:02       11 阅读
  6. PyQt5 强制退出进程

    2024-06-13 21:46:02       10 阅读
  7. jquery.PrintArea.js 设置不打印

    2024-06-13 21:46:02       11 阅读
  8. Linux 和 分区

    2024-06-13 21:46:02       11 阅读