[技巧]go语言使用select{}阻塞main函数和for range 做定时器服务

本文介绍如何使用Go语言的select{}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

go语言使用select{}阻塞main函数和for range 做定时器服务

  • 1.在做游戏服务器时,我们需要程序启动时就开启n个协程,然后不用做任何服务(不占用CPU时间),但是不能退出。我们可以用下面的代码实现。
  • 2.有些情况下,我们需要定时的去运行一段服务(代码),有多GO友,首先想到是time包,下面是一种简单的定时服务,逻辑简单,但是也存在一定的风险,需要GO友对goroutine有很深的理解,避免协程之间发生阻塞。

有些情况下,需要让main函数不退出,让它在后台一直执行,我们可以利用 select{}阻塞:

for range不仅能遍历map,slice,array还能取出channel中数据,range前面可以不用变量接收,time.Tick()返回的是一个channel,每隔指定的时间会有数据从channel中出来,

1.直接上代码

func main(){
    for i := 0; i < 20; i++ { //启动20个协程处理消息队列中的消息
        go thrind(i)
    }
    select {} // 阻塞
}
func thrind( i int){
    for range time.Tick(1000 * time.Millisecond) {  
        fmt.Println("\n 线程:",i)
    }
}

2下面的代码对 select{}阻塞 的使用是错的,select{}阻塞需要有线程在运行

func main(){
    for i := 0; i < 20; i++ { //启动20个协程处理消息队列中的消息
        go thrind(i)
    }
    select {} // 阻塞
}
func thrind( i int){

}

运行后报错:
fatal error: all goroutines are asleep - deadlock!

<think>好的,我现在需要帮助用户解决如何在Go语言中实现一个每5秒打印一次'hello'的定时器的问题。首先,我应该回顾一下用户提供的引用内容,看看有没有相关的示例或者建议。 用户提供的引用中有几个提到了定时器的实现,比如引用[2]中的test_ticker函数使用了time.NewTicker,而引用[4]中的代码示例也用了time.NewTicker,并且设置间隔为5秒。这两个例子应该可以作为参考。另外,引用[3]提到使用sync.WaitGroup来同步并发任务,但用户的问题可能不需要同步,只需要持续运行定时器,所以可能不需要WaitGroup。 接下来,我需要确保代码的正确性。根据Go语言的标准库,time.NewTicker会创建一个周期性的定时器,每隔指定的时间就会向通道发送一个时间事件。然后,用户可以通过一个无限循环来读取这个通道,从而执行定期任务。 用户的需求是每5秒打印一次'hello',所以应该设置间隔为5秒。需要注意的是,time.NewTicker的参数是time.Duration类型,所以需要写成5 * time.Second。另外,为了避免资源泄漏,当定时器不再需要时,应该调用Stop()方法停止它。不过,如果程序是无限运行的,比如在main函数中持续运行,可能不需要停止,但为了代码的规范性,最好在适当的时候停止。 引用[4]中的代码示例有一个问题,它在select语句中两次读取ticker.C,一次在case语句,另一次在fmt.Println中。这会导致错过一个tick,因为每次case读取一次,然后再次读取时可能没有数据,导致阻塞。正确的法应该是只读取一次,然后将时间值传递给打印语句。例如: case t := <-ticker.C: fmt.Println(t, "hello") 这样就能正确捕获每次的tick事件。 另外,用户可能希望程序一直运行,直到手动终止,所以需要一个无限循环,比如for循环配合select语句,或者直接使用range来遍历ticker.C通道。例如: for t := range ticker.C { fmt.Println(t, "hello") } 但需要注意,如果使用range,当ticker被停止时,循环才会退出,所以需要适当的处理。 综合以上分析,正确的代码应该使用time.NewTicker(5 * time.Second),然后在循环中读取通道,并正确打印信息。同时,要处理可能的资源释放,比如在defer中调用Stop()。 现在需要检查用户提供的引用是否有其他需要注意的地方。引用[5]提到runtime包定时器的相关内容,但可能不直接影响当前问题。引用[3]的sync.WaitGroup在这里可能不需要,因为程序可能需要一直运行,不需要等待其他goroutine完成。 最后,确保代码示例简洁明了,符合Go的最佳实践,比如正确处理ticker的停止,避免资源泄漏。同时,可能需要添加注释说明代码的结构,帮助用户理解。</think>### Go语言实现5秒定时打印的两种方法 根据引用[2][4]中的定时器实现方案,这里提供两种标准实现方式: #### 方法一:使用无限循环+select ```go package main import ( "fmt" "time" ) func main() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() // 保证退出时释放资源[^2] for { select { case t := <-ticker.C: // 正确读取方式(修复引用[4]的双重读取问题) fmt.Printf("%v: hello\n", t.Format("2006-01-02 15:04:05")) } } } ``` #### 方法二:使用range遍历通道 ```go package main import ( "fmt" "time" ) func main() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for t := range ticker.C { // 更简洁的遍历方式 fmt.Printf("%v: hello\n", t.Format("2006-01-02 15:04:05")) } } ``` **关键点说明**: 1. `time.NewTicker(5 * time.Second)` 创建5秒间隔的定时器 2. 必须使用`defer ticker.Stop()`避免资源泄漏 3. 时间格式化需使用Go的基准时间`2006-01-02 15:04:05` 4. 两种方法都会永久运行,可通过`Ctrl+C`终止 **性能优化建议**: - 如需动态调整间隔时间,可重建ticker - 需要精准时间补偿时,推荐使用`time.Timer`[^5] - 高并发场景建议配合`sync.WaitGroup`管理goroutine[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值