golang 常用控制协程的三种方式

golang的协程是没有相互的依赖关系的

package main

import (
	"fmt"
	"time"
)

func main() {
	go func() {
		fmt.Println("此处为父协程")

		go func() {
			for {
				time.Sleep(time.Second * 2)
				fmt.Println("此处为子协程")
			}

		}()
		defer fmt.Println("父协程执行完毕")
		return
	}()
	time.Sleep(time.Second * 10)
	fmt.Println("exit")
}

执行上面的代码就可以看出golang里,协程都是互相独立的,没有依赖(父子)关系。main函数本身也运行在一个goroutine中,main是所有协程的被依赖者是一个特例,所以我们就需要对我们创造的协程进行控制,常用到的协程控制有以下三种方式

waitGroup

waitGroup这种方式适用于一个任务可以被拆分成几个子任务,并且子任务之间的关联程度不高,全部的子任务都完成,才会进行下一阶段的任务。

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(3)

	go func() {
		defer wg.Done()
		time.Sleep(time.Second * 1)
		fmt.Println("任务1执行完成")
	}()
	go func() {
		defer wg.Done()
		time.Sleep(time.Second * 2)
		fmt.Println("任务2执行完成")
	}()
	go func() {
		defer wg.Done()
		time.Sleep(time.Second * 3)
		fmt.Println("任务3执行完成")
	}()

	wg.Wait()
	fmt.Println("全部任务执行完成")

}

channel

当满足某一种需要,通知协程不再继续工作的时候,就需要用到channel,channel主要应用于协程之间的通讯

package main

import (
	"fmt"
	"time"
)

func main() {
	var signal = make(chan struct{})

	go func() {
		for {
			select {
			case <-signal:
				fmt.Println("当前任务已停止")
				return
			case <-time.After(time.Second * 2):
				fmt.Println("任务执行中")
			}
		}
	}()

	time.Sleep(time.Second * 10)
	signal <- struct{}{}
	fmt.Println("exit")
}

context

当多个goroutine都需要控制结束,或者这些goriutine所衍生出来的goroutine也需要进行控制的时候就需要用到context,多层级goroutine之间的信号传播需要使用context。

package main

import (
	"context"
	"fmt"
	"time"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	go gOne(ctx, "任务一")
	time.Sleep(time.Second * 10)
	cancel()
	time.Sleep(time.Second * 2)
	fmt.Println("exit")
}

func gOne(ctx context.Context, name string) {
	go gTwo(ctx, "任务二")
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name + ":任务已停止")
			return
		case <-time.After(time.Second * 1):
			fmt.Println(name + "任务执行中")
		}
	}
}

func gTwo(ctx context.Context, name string) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name + ":任务已停止")
			return
		case <-time.After(time.Second * 2):
			fmt.Println(name + "任务执行中")
		}
	}
}
posted @ 2023-06-24 09:54  元気田支店长  阅读(509)  评论(0编辑  收藏  举报