简单得说,如果两个channel同时到达,case的消费顺序是随机的。
参考:https://studygolang.com/articles/28353?fr=sidebar
下面的代码可以保证select的时候case rs := <-ch:先执行, case <-done:最后执行,原因是make(chan *int)由于长度不够,所以它会阻塞后被消费才释放。

func TestSelect(t *testing.T) {
	ch := make(chan *int)
	len := 100
	wg := sync.WaitGroup{}
	wg.Add(len)
	done := make(chan struct{})
	for i := 0; i < len; i++ {
		iC := i
		go func() {
			defer wg.Done()
			// 此行代码阻塞, 由于channel长度不够的原因, 当被消费后释放
			ch <- &iC
		}()
	}
	go func() {
		wg.Wait()
		done <- struct{}{}
	}()
	time.Sleep(time.Second)
	ans := make([]*int, 0)
waitLoop:
	for {
		fmt.Println("for ...")
		select {
		case <-done:
			fmt.Println("done")
			break waitLoop
		case rs := <-ch:
			fmt.Println("case", *rs)
			time.Sleep(time.Millisecond * 10)
			ans = append(ans, rs)
			time.Sleep(time.Millisecond * 10)
		}
	}
	for _, v := range ans {
		fmt.Printf("%v ", *v)
	}
}

func TestSelect2(t *testing.T) {
	ch := make(chan int)
	go func() {
		ch <- 1
		fmt.Println("<-结束")
	}()
	time.Sleep(time.Second * 5)
	fmt.Println("5秒后")
	select {
	case i := <-ch:
		fmt.Println("<-", i)
	}
}