3. 如何控制协程执行顺序

此开源图书由ithaiq原创,创作不易转载请注明出处

对应两个协程勿扰质疑可以通过两个channel先后触发即可,还可以交替执行

如交替打印数字和字母,实现如下效果:12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ

func main() {
	wg := &sync.WaitGroup{}
	numChan := make(chan struct{}, 1)
	byteChan := make(chan struct{}, 1)
	wg.Add(2)
	numChan <- struct{}{}
	go numPrint(wg, numChan, byteChan)
	go bytePrint(wg, numChan, byteChan)
	wg.Wait()
}

func numPrint(wg *sync.WaitGroup, numChan, byteChan chan struct{}) {
	i := 1
	for {
		if i == 27 {
			wg.Done()
			break
		}
		<-numChan
		println(i, i+1)
		i += 2
		byteChan <- struct{}{}
	}
}

func bytePrint(wg *sync.WaitGroup, numChan, byteChan chan struct{}) {
	i := 'A'
	for {
		if i > 'Z' {
			wg.Done()
			break
		}
		<-byteChan
		fmt.Printf("%c%c", i, i+1)
		i += 2
		numChan <- struct{}{}
	}
}

延伸开来,如果N个协程如何控制执行顺序?考虑使用sync.Cond

var co *sync.Cond
var group int

func work1() {
	fmt.Println("work1")
	for i := 1; i <= 3; i++ {
		//业务处理
		co.L.Lock()
		group = i
		co.L.Unlock()
		co.Broadcast()
		time.Sleep(time.Second * 1)
	}
}

func work2() {
	co.L.Lock()
	for group != 2 {
		co.Wait()
	}
	time.Sleep(time.Second * 4)
	fmt.Println("work2")
	co.L.Unlock()
}

func work3() {
	co.L.Lock()
	for group != 3 {
		co.Wait()
	}
	time.Sleep(time.Second * 2)
	fmt.Println("work3")
	co.L.Unlock()
}

func dowork(wg *sync.WaitGroup, fns ...func()) {
	for _, fn := range fns {
		wg.Add(1)
		go func(fn func()) {
			defer wg.Done()
			fn()
		}(fn)
	}
}
func main() {
	var wg sync.WaitGroup
	co = sync.NewCond(new(sync.Mutex))
	dowork(&wg, work1, work2, work3)
	wg.Wait()
}

如上代码演示主要是Broadcast广播任意goroutine都能收到Wait解除阻塞,然后通过互斥锁mutex控制全局变量group,而group再去控制执行顺序

最后更新于

这有帮助吗?