找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 459|回复: 0

[go基础] golang中time.After一直无法跳出select循环

[复制链接]
发表于 2023-4-1 20:41 | 显示全部楼层 |阅读模式

问题的代码如下,在for select 循环中,本想通过 time.After 设置超时时间,但一直无法退出。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	ch := make(chan int)

	go func() {
		for v := range ch {
			fmt.Println(v)
		}
	}()
END:
	for {
		select {
		case ch <- rand.Int():
		case <-time.After(time.Second * 3):
			fmt.Println("timeout")
			break END
		}
		time.Sleep(time.Second)
	}
}

控制台始终打印出从通道 ch 中读取的随机数,time.After 一直没能等到。

原因是每次进入到 case <-time.After(time.Second * 3): 时,都会创建一个新的通道返回,所以这个 case 每次都在等待接收新的通道的数据,永远不可能等到。

time.After 方法的源码如下:

func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

每次调用都会通过 NewTimer 创建一个新的 Timer,并且 Timer.C 也是新创建的通道。

func NewTimer(d Duration) *Timer {
	c := make(chan Time, 1)
	t := &Timer{
		C: c,
		r: runtimeTimer{
			when: when(d),
			f:    sendTime,
			arg:  c,
		},
	}
	startTimer(&t.r)
	return t
}

为了解决上面的问题,我们可以把 time.After 放在 for 循环外面,来解决此问题。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	ch := make(chan int)
	timer := time.After(time.Second * 3)

	go func() {
		for v := range ch {
			fmt.Println(v)
		}
	}()
END:
	for {
		select {
		case ch <- rand.Int():
		case <-timer:
			fmt.Println("timeout")
			break END
		}
		time.Sleep(time.Second)
	}
}

源文地址:https://www.cnblogs.com/jkko123/p/12733487.html

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|学习笔记

GMT+8, 2024-9-8 09:30 , Processed in 0.032536 second(s), 13 queries , APCu On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表