go中的select

go中的select提供了一种方式来处理多个channels,select语句满足如下条件

  1. 每个channel的值都会被计算
  2. 如果没有channel有产出的话,会阻塞直到一个channel产出
  3. 如果多个channel有产出的话,会假随机(pseudo-randomly)的选择一个产出
  4. 在有default语句的情况下,没有channel准备好的时候,会立即执行default的语句

下面有一个实例,源码中对boring返回结果的注释(第一行末尾的注释)直译是返回一个只接受string类型的channel。但是个人觉得翻译为返回的是一个只读的string类型的channel更好,因为后续的对c的操作,都只能从c中读取string

func boring(msg string) <-chan string { // Returns receive-only channel of strings.
    c := make(chan string)
    go func() { // We launch the goroutine from inside the function.
        for i := 0; ; i++ {
            c <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
        }
    }()
    return c // Return the channel to the caller.
}
func fanIn(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    go func() {
        for {
            select {
            case s := <-input1:  c <- s
            case s := <-input2:  c <- s
            }
        }
    }()
    return c
}
func main() {
	joe := boring("Joe")
	ann := boring("Ann")
	c := fallin(joe, ann)
	for i := 0; i < 20; i++ {
		fmt.Println(<-c)
	}
	fmt.Println("You're both boring; I'm leaving.")
}

产生的结果如下,其中由于每个boring中的sleep的时间不确定,所以导致结果是Joe最终对应的i为10,而Ann最终对应的i为8

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
Joe 5
Ann 5
Joe 6
Ann 6
Ann 7
Joe 7
Joe 8
Joe 9
Ann 8
Joe 10
You're both boring; I'm leaving.

select语句满足的条件1是值得思考的,每个channel都是需要计算取值的,因为没有正确的理解这句话是可能犯错误的。
可以思考下面这个函数的输出,三秒之后函数会停止执行吗?

func main() {
	c := boring("Joe")
	for {
		select {
		case s := <-c:
			fmt.Println(s)
		case <- time.After(3 * time.Second):
			fmt.Println("Your're too slow")
			return
		}
	}
}

答案是不会的,因为每次执行到select语句中的各个选项的时候,都会计算每个case中的值。相当于在第一次输出c的产出之后,第二次进入select的选择的时候,time.After()就又重新开始计时了。要想在三秒之后停止这个函数,需要调整time.After的位置到select执行之前。

func main() {
	c := boring("Joe")
    timeout := time.After(3 * time.Second)
	for {
		select {
		case s := <-c:
			fmt.Println(s)
		case <- timeout:
			fmt.Println("Your're too slow")
			return
		}
	}
}

本文内容翻译自 Go Concurrency Patterns
做一个知识型讨饭的,有些闲钱的,觉得对你有用的可以捐点

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章