掌握 Go 的计时器

简介

定时器是任何编程语言的重要工具,它允许开发人员在特定时间间隔安排任务或执行代码。在 Go 中,定时器是通过 time 包实现的,该包提供了一系列功能来创建、启动、停止和有效处理定时器。我们将探索 Go 中定时器的强大功能,并通过代码示例演示如何在应用程序中使用定时器。

创建计时器

要在 Go 中创建一个定时器,我们可以使用 time.NewTimer() 函数,该函数将持续时间作为参数。下面是一个示例:

go 复制代码
func CreateTimer() {
	timer := time.NewTimer(2 * time.Second)
	fmt.Println("Timer created.")

	<-timer.C // 阻塞
	fmt.Println("Timer expired.")
}

在上述代码片段中,我们使用 time.NewTimer() 创建了一个持续时间为 2 秒的新定时器。<-timer.C 语句会阻塞执行,直到定时器过期。定时器到期后,"Timer expired."(定时器已过期)信息将打印到控制台。

停止计时器

在某些情况下,您可能想在定时器到期前停止它。为此,您可以使用定时器对象的 Stop() 方法。让我们修改之前的示例,加入定时器停止功能:

go 复制代码
func StopTimer() {
	timer := time.NewTimer(2 * time.Second)
	fmt.Println("Timer created.")

	go func() {
		<-timer.C
		fmt.Println("Timer expired.")
	}()

	time.Sleep(1 * time.Second)
	stopped := timer.Stop()
	if stopped {
		fmt.Println("Timer stopped.")
	} else {
		fmt.Println("Timer has already expired.")
	}
}

在更新后的代码中,我们创建了一个 goroutine 来处理定时器过期,这样就可以在定时器过期前停止它。我们使用 time.Sleep() 函数来模拟在尝试停止计时器之前正在进行的一些工作。最后,我们调用 timer.Stop() 停止定时器。如果定时器已过期,timer.Stop() 返回 false,并打印 "定时器已过期"。否则,我们将打印 "定时器已停止"。

重置计时器

Go 还提供了重置活动定时器的方法。通过 Reset() 方法,您可以更改活动定时器的持续时间,重新开始倒计时。下面是一个示例:

go 复制代码
func ResetTimer() {
	timer := time.NewTimer(10 * time.Second)
	fmt.Printf("time: %d, Timer created.\n", time.Now().Unix())

	time.Sleep(2 * time.Second)
	reset := timer.Reset(3 * time.Second)
	if reset {
		fmt.Printf("time: %d, Timer reset.\n", time.Now().Unix())
	} else {
		fmt.Printf("time: %d, Timer has already expired.\n", time.Now().Unix())
	}
	<-timer.C // 阻塞
	fmt.Printf("time: %d, Timer expired again.\n", time.Now().Unix())
}

输出为:

go 复制代码
time: 1695183503, Timer created.
time: 1695183505, Timer reset.
time: 1695183508, Timer expired again.

在上述代码中,我们创建了一个持续时间为 10 秒的计时器。使用 time.Sleep() 等待 2 秒后,我们调用 timer.Reset(),新的持续时间为 3 秒。如果定时器尚未过期,则重置操作成功,我们将打印 "定时器重置"。否则,进入到 <-timer.C 阻塞阶段,然后打印 我们将打印 "Timer expired again."。

重置定时器与停止定时器

了解重置定时器和使用 Stop() 停止定时器之间的区别非常重要。

go 复制代码
func CompareResetAndStop() {
	timer := time.NewTimer(5 * time.Second)
	fmt.Printf("time: %d, Timer created.\n", time.Now().Unix())

	go func() {
		<-timer.C
		fmt.Printf("time: %d, Timer expired.\n", time.Now().Unix())
	}()

	time.Sleep(2 * time.Second)
	timer.Reset(3 * time.Second)
	fmt.Printf("time: %d, Timer reset.\n", time.Now().Unix())

	time.Sleep(2 * time.Second)
	timer.Stop()
	fmt.Printf("time: %d, Timer stopped.\n", time.Now().Unix())
}

输出为:

go 复制代码
time: 1695183802, Timer created.
time: 1695183804, Timer reset.
time: 1695183806, Timer stopped.

在本例中,我们创建了一个持续时间为 5 秒的计时器。2 秒后,我们使用 timer.Reset() 将计时器重置为 3 秒。之后,再过 2 秒,我们使用 timer.Stop() 停止计时器。重置定时器会改变其持续时间并重新开始倒计时,而停止定时器则会立即停止执行,无论剩余持续时间多长。

带 Ticker 的计时器

Go 提供了一种 Ticker 类型,它是一种专门的定时器,可在指定的时间间隔内重复触发。定时器可用于定期执行任务。

go 复制代码
func Tick() {
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	go func() {
		for range ticker.C {
			fmt.Printf("time: %d, Ticker ticked!\n", time.Now().Unix())
		}
	}()

	time.Sleep(5 * time.Second)
}

在本例中,我们使用 time.NewTicker() 创建了一个持续时间为 1 秒的 Ticker。然后,我们启动一个 goroutine,从 ticker.C channel 接收值,每当滴答声响起时,goroutine 就会发出一个值。在 goroutine 中,每次接收到一个 tick 时,我们都会打印 "Ticker ticked!"。调用 time.Sleep() 可以让滴答滴答运行 5 秒钟,然后退出程序。

使用 Select 的超时

Go 的 select 语句允许在多个通道上执行非阻塞操作。这可以用来使用计时器实现超时。

go 复制代码
func TimeOut() {
	ch := make(chan string)

	go func() {
		time.Sleep(2 * time.Second)
		ch <- "Operation completed."
	}()

	select {
	case msg := <-ch:
		fmt.Println(msg)
	case <-time.After(1 * time.Second):
		fmt.Println("Timeout reached.")
	}
}

在本例中,我们创建了一个 channel ch,并启动一个 goroutine 来模拟耗时 2 秒的操作。我们使用 select 语句从 ch 接收信息,或使用 time.After() 等待超时。如果操作在 1 秒内完成,则打印消息。否则,将执行超时情况,并打印 "Timeout reached."。

相关推荐
潘多编程1 小时前
Spring Boot微服务架构设计与实战
spring boot·后端·微服务
2402_857589362 小时前
新闻推荐系统:Spring Boot框架详解
java·spring boot·后端
2401_857622662 小时前
新闻推荐系统:Spring Boot的可扩展性
java·spring boot·后端
Amagi.3 小时前
Spring中Bean的作用域
java·后端·spring
侠客行03173 小时前
xxl-job调度平台之任务触发
java·后端·源码
2402_857589363 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
J老熊4 小时前
Spring Cloud Netflix Eureka 注册中心讲解和案例示范
java·后端·spring·spring cloud·面试·eureka·系统架构
Benaso4 小时前
Rust 快速入门(一)
开发语言·后端·rust
sco52824 小时前
SpringBoot 集成 Ehcache 实现本地缓存
java·spring boot·后端
原机小子4 小时前
在线教育的未来:SpringBoot技术实现
java·spring boot·后端