关于计算Select中获取资料的时长

来源:11-4 用select进行调度

憨憨Paul

2021-11-15

package main

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

func createWorker(id int) chan<- int {
	c := make(chan int)
	go worker(id, c)
	return c
}

func worker(id int, c chan int) {
	for n := range c {
		fmt.Printf("Worker %d received %d\n", id, n)
	}
}

// 构建器
func generator() chan int {
	out := make(chan int)
	go func() {
		i := 0
		// 间隔 150 ms
		for ; ; time.Sleep(time.Duration(rand.Intn(150)) * time.Millisecond) {
			// 发送数据
			out <- i
			i++
		}
	}()
	return out
}

func main() {

	var (
		c1     = generator()
		c2     = generator()
		worker = createWorker(0)
		n      = 0
		values = make([]int, 0)
		// 添加定时器
		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): // Question
			fmt.Println("time out")
		case <-tm: // 定时器时间到了就自动关闭
			fmt.Println("bye")
			return
		}
	}
}

对标记注解Question产生的一些想法
虽然 Select 是对 channel 的非堵塞式接收处理方案
但是在没有 default 的情况下
Select 内部还是会把所有的资料都接收完毕再做操作
所以当 c1 & c2 & activeValue & tm 没有要传送资料时
整个 Select 将会处于停滞状态,
那么当时间超过800毫秒时
那么第四个 case 就将会接收到数据,从而执行对应的程式码

写回答

1回答

ccmouse

2021-11-15

select中所有的case会先被执行,然后再进行等待。

c1 & c2 & activeWorker(注意是Worker不是Value) & tm,它们的执行结果就是本身。

time.After(800 * time.Millisecond),这个也要先被执行,time.After函数返回一个chan Time。

好了,至此所有的执行结束,开始进入等待。如果800毫秒c1 & c2 & activeWorker & tm都没有等到/发送数据,那么此时就会在time.After函数返回的chan Time里收到数据,触发第4个case 

0
0

Google资深工程师深度讲解Go语言 由浅入深掌握Go语言

语法+分布式爬虫实战 为转型工程师量身打造

5995 学习 · 1909 问题

查看课程