写一个Goroutine工作池

75 阅读1分钟
package main

import (
	"fmt"
	"time"
)

//创建一个连接池里来实现一个通用的限定Groutine动态保活的工作池

//如何确定一个Goroutine已经死亡

//在子Goroutine的业务中,定期写一个KeepLive的Channel,然后由主Goroutine来发现当前子Go的状态。
/*
如何做到得知一个Goroutine的死亡呢
子 Groutine
可以通过一个被监控的Goroutine添加一个defer,当recover()捕获到当前Goroutine的异常状态时,通过channel给主Goroutine发送一个死亡信号。
主 Groutine
在主Groutine上,从这个channel读取内容,当读到内容时就重启子Goroutine,主Goroutine需要记录子Goroutine的ID。
*/
type Worker struct {
	id  int
	err error
}

type WorkManager struct {
	//用来监控Worker是否已经死亡的缓冲channel
	workerChan chan *Worker
	//一共要监控的Work的数量
	nWorkers int
}

//创建一个WorkerManager对象
func NewWorkerManager(nworkers int) *WorkManager {
	return &WorkManager{
		nWorkers:   nworkers,
		workerChan: make(chan *Worker, nworkers),
	}
}

//启动worker池,并为每个Worker分配一个ID,让每个Worker进行工作
func (wm *WorkManager) StartWorkerPool() {
	//开启一定数量的worker
	for i := 0; i < wm.nWorkers; i++ {
		i := i
		wk := Worker{
			id:  i,
			err: nil,
		}
		go wk.work(wm.workerChan)
	}

	//启动保活
	wm.KeepLiveWorkers()

}

func (wm *WorkManager) KeepLiveWorkers() {
	for wk := range wm.workerChan {
		fmt.Printf("wk.id: %v\n", wk.id)
		fmt.Printf("wk.err: %v\n", wk.err)

		wk.err = nil
		go wk.work(wm.workerChan)
	}
}

func (wk *Worker) work(workerChan chan<- *Worker) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if err, ok := r.(error); ok {
				wk.err = err
			} else {
				wk.err = fmt.Errorf("panic happend with [ %v ]", r)
			}
		} else {
			wk.err = err
		}

		//通知主Goroutine,当前子Goroutine已经死亡
		workerChan <- wk
	}()

	//业务代码
	fmt.Printf("wk.id: %v\n", wk.id)

	for i := 0; i < 5; i++ {
		time.Sleep(time.Second * 1)
	}

	panic("work panic")

	return err
}

func main() {
	wm := NewWorkerManager(100000000)
	wm.StartWorkerPool()
}