管理Goroutine的三种方式:waitGroup, channel, context

waitGroup

使用范围:当一个工作需要被拆分成多个子工作,需要等待全部的子工作处理完成后才能进行下一步工作的时候,一般使用waitGroup。
代码示例:

func main() {
     
	wg := sync.WaitGroup{
     }

	for i:=1; i<=3; i++ {
     
		wg.Add(1) 		// 开始每一个goroutine之前都需要执行这句
		go func(num int) {
     
			defer wg.Done()		// 表示该goroutine完成
			fmt.Printf("执行任务%d\n", num)
		}(i)
	}
	wg.Wait()
}

channel

使用范围:用于关闭goroutine。当有一个或几个Goroutine在后台执行一些任务的时候,在主程序结束前通过channel来通知这些goroutine关闭。
代码示例:

func main() {
     
	ch := make(chan struct{
     })

	for i:=1; i<=3; i++ {
     
		go func(num int) {
     
			fmt.Printf("开始执行任务%d。\n", num)
			for {
     
				select {
     
				case <-ch:
					fmt.Printf("任务%d结束。\n", num)
					return
				case <-time.After(time.Second):
					fmt.Printf("任务%d等待1秒。\n", num)
				}
			}
		}(i)
	}

	time.Sleep(time.Second*3)

	close(ch)
	time.Sleep(time.Second)
}

context

适用范围:context相比于单独使用channel来通知goroutine关闭有着更加复杂的功能,适用于通知有多层的goroutine关闭。

func foo(ctx context.Context)  {
     
	go bar(ctx)
	for {
     
		select {
     
		case <-ctx.Done():
			fmt.Println("foo exit")
			return
		case <-time.After(time.Second):
			fmt.Println("foo do something")
		}
	}
}

func bar(ctx context.Context)  {
     
	for {
     
		select {
     
		case <-ctx.Done():
			fmt.Println("bar exit")
			return
		case <-time.After(time.Second):
			fmt.Println("bar do something")
		}
	}
}

func main() {
     
	ctx, cancel := context.WithCancel(context.Background())

	go foo(ctx)

	time.Sleep(time.Second*3)
	cancel()
	time.Sleep(time.Second)
}

你可能感兴趣的:(Go)