掌握 Go 的计时器

TimLiuDream · · 1145 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

# 简介 定时器是任何编程语言的重要工具,它允许开发人员在特定时间间隔安排任务或执行代码。在 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."。 > 关注公众号【爱发白日梦的后端】分享技术干货、读书笔记、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力!

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1145 次点击  ∙  1 赞  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传