请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

Select case <-time.After 工作问题

tm := time.After(10 * time.Second)
for {
	var activeWorker chan<- int
	var activeValue int
	if len(values) > 0 {
		activeWorker = worker
		activeValue = values[0]
	}
	select {
	case n := <-c1:
		values = append(values, n)
	case n := <-c2:
		values = append(values, n)
	case activeWorker <- activeValue:
		values = values[1:]
	case <-time.After(800 * time.Millisecond):
		fmt.Println("Time out")
	case <-tm:
		fmt.Println("byte")
		return
	}
}

老师的例子中分别出现两种创建 <-chan Time 的方法,

tm创建在循环体的外面,这个比较容易理解,也就是启动一个 携程然后,我们使用select看他有没有送出值

而第2中在 case中创建,这个我就不清楚了,每次for{}在运行时每个case都会看看是不是有值,要是没有就结束select,而每次我们都创建一个新的定时器携程(可以理解成阻塞的发射器吧),在创建了新的<-chan Time之后前一个<-chan Time的携程岂不是没有地方接收了?由于在这一轮for中的case是一个新的<-chan Time,新的<-chan Time计时应该是也是以当前时间开始的,这么一来就算是超时那不也是检测不到了呀?然而事实上和我的预期有出入。

我的理解是不是出错了老师?

后我又换了种思路来考虑这个问题,也就是说此select所有case都是并行的执行的,那么这样一来考虑所有的case都被阻塞<-chan Time到时间后解除阻塞,这么思考就能符合输出的结果。但是这样又和defaultcase顺序的意义相冲突?他们的顺序是没有意义的吗?

下面是 time.After函数的

func After(d Duration) <-chan Time {
	return NewTimer(d).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
}

可以看到这个NewTimer 每次都make了新的内存空间创建了一个全新的Timer

正在回答 回答被采纳积分+3

1回答

ccmouse 2019-12-04 20:04:20

你的第二个理解是正确的,所有条件都是并行等的,谁先有数据就选择谁,没有先后的说法。如果两个case同时有数据,会随机选择。
感觉你有可能和switch..case..搞起来了。switch..case..是有顺序的。另外default在select里的作用是,如果所有的分支都block着,那么一个都不等待直接进default这个case去执行。这可以用来non-blocking的从channel读取数据

1 回复 有任何疑惑可以回复我~
  • 提问者 Cliven_cn #1
    default 是有意义的,就是说如果不出现default,运行select的这个 携程会被case所有的case所阻塞,出现了default之后为,就会忽略阻塞直接到default中。
    
    在老师的例子中,是没有default语句的,也就是说在任意case得到或发出数据之前,运行这个select自然会被阻塞,那么for就不会进入新的一轮循环,自然每次创建一个Timer是没有问题的
    回复 有任何疑惑可以回复我~ 2019-12-04 21:26:48
  • ccmouse 回复 提问者 Cliven_cn #2
    这是对的
    回复 有任何疑惑可以回复我~ 2019-12-04 21:38:40
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信