golang 控制goroutine调度顺序

使用go关键字就可以很容易的启动一个goroutine,启动后他们的执行顺序是不能保证的。如果有多个goroutine,怎样按照我想要的顺序来执行呢?

如:

  • a1在b1和c1后面执行(b1和c1都执行完a1才能执行)
  • d1在a1后面执行(d1执行完才能执行a1)
  • e1在b1或者c1后面执行(b1或者c1有一个执行完就可以执行e1)

下面代码演示了怎样解决上面问题:
event/event.go

package event

import (
	"reflect"
	"sync"
	"sync/atomic"
)

type Event struct {
	fired int32
	c     chan struct{}
	once  sync.Once
}

func New() *Event {
	return &Event{c: make(chan struct{})}
}

func (ev *Event) Fire() int32 {
	atomic.AddInt32(&ev.fired, 1)
	ev.once.Do(func() {
		close(ev.c)
	})
	return ev.fired
}

func (ev *Event) Wait() {
	<-ev.c
}

func (ev *Event) HasFired() bool {
	return atomic.LoadInt32(&ev.fired) > 0
}

func (ev *Event) Start(f func()) {
	go func() {
		defer ev.Fire()
		f()
	}()
}

func (ev *Event) After(f func(), e *Event) {
	go func() {
		defer ev.Fire()
		e.Wait()
		f()
	}()
}

func (ev *Event) Every(f func(), evs ...*Event) {
	go func() {
		defer ev.Fire()
		for _, e := range evs {
			e.Wait()
		}
		f()
	}()
}

func (ev *Event) Some(f func(), evs ...*Event) {
	var selectCase = make([]reflect.SelectCase, len(evs))
	for i, e := range evs {
		selectCase[i].Dir = reflect.SelectRecv
		selectCase[i].Chan = reflect.ValueOf(e.c)
	}

	go func() {
		defer ev.Fire()
		reflect.Select(selectCase)
		f()
	}()
}

main.go

package main

import (
	"fmt"
	"time"

	"godemo/event"
)

func main() {
	a1 := event.New()
	b1 := event.New()
	c1 := event.New()
	d1 := event.New()
	e1 := event.New()

	// a1在b1和c1后面
	a1.Every(func() {
		fmt.Println("a1")
	}, b1, c1)

	b1.Start(func() {
		time.Sleep(100 * time.Millisecond)
		fmt.Println("b1")
	})

	c1.Start(func() {
		time.Sleep(1 * time.Second)
		fmt.Println("c1")
	})

	// d1在a1后面
	d1.After(func() {
		fmt.Println("d1")
	}, a1)

	// e1在b1或c1后面
	e1.Some(func() {
		fmt.Println("e1")
	}, b1, c1)

	time.Sleep(2 * time.Second)
}

再举个例子,如a, b, c, d按倒序执行:

package main

import (
	"fmt"

	"godemo/event"
)

func main() {
	a1 := event.New()
	b1 := event.New()
	c1 := event.New()
	d1 := event.New()

	a1.After(func() {
		fmt.Println("a1")
	}, b1)

	b1.After(func() {
		fmt.Println("b1")
	}, c1)

	c1.After(func() {
		fmt.Println("c1")
	}, d1)

	d1.Start(func() {
		fmt.Println("d1")
	})

	a1.Wait()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值