ggzeng
10/22/2019 - 6:08 AM

receive channel exit

接收channel如何优雅的退出


// 1. 场景:只有一个接收通道。使用for range,如果channel关闭则会自动退出循环
go func(in <-chan int) {
    // Using for-range to exit goroutine
    // range has the ability to detect the close/end of a channel
    for x := range in {
        fmt.Printf("Process %d\n", x)
    }
}(inCh)

// 2. 场景:接收多通道,但是只要有一个通道关闭就结束。使用select ok,如果channel关闭,则ok为false
go func() {
	for {   // in for-select using ok to exit goroutine
		select {
		case x, ok := <-in:
			if !ok {
				return
			}
			fmt.Printf("Process %d\n", x)
			processedCnt++
		case <-t.C:
			fmt.Printf("Working, processedCnt = %d\n", processedCnt)
		}
	}
}()

// 3. 场景:接收多个通道,只有所有通道都关闭才退出。使用select ok,并把关闭的channel置为nil(这样不会被select到)
go func() {
	for {  // in for-select using ok to exit goroutine
		select {
		case x, ok := <-in1:
			if !ok {
				in1 = nil
			}
			// Process
		case y, ok := <-in2:
			if !ok {
				in2 = nil
			}
			// Process
		case <-t.C:
			fmt.Printf("Working, processedCnt = %d\n", processedCnt)
		}

		// If both in channel are closed, goroutine exit
		if in1 == nil && in2 == nil {
			return
		}
	}
}()

// 4. 场景:有独立的退出通知通道,可以主动退出
func worker(stopCh <-chan struct{}) {
	go func() {
		defer fmt.Println("worker exit")
		// Using stop channel explicit exit
		for {
			select {
			case <-stopCh:
				fmt.Println("Recv stop signal")
				return
			case <-t.C:
				fmt.Println("Working .")
			}
		}
	}()
	return
}