func (p *taskPoolSimple) stop() {
	select {
	case <-p.done:
		return
	default:
		p.once.Do(func() {
			close(p.done)
			close(p.work)
		})
	}
}
stop all tasks
package gxsync
import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"runtime"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"
)
import (
	gxruntime "github.com/dubbogo/gost/runtime"
)
type task func()
type GenericTaskPool interface {
	AddTask(t task) bool
	AddTaskAlways(t task)
	AddTaskBalance(t task)
	Close()
	IsClosed() bool
}
func goSafely(fn func()) {
	gxruntime.GoSafely(nil, false, fn, nil)
}
type TaskPool struct {
	TaskPoolOptions
	idx    uint32  
	qArray []chan task
	wg     sync.WaitGroup
	once sync.Once
	done chan struct{}
}
func NewTaskPool(opts ...TaskPoolOption) GenericTaskPool {
	var tOpts TaskPoolOptions
	for _, opt := range opts {
		opt(&tOpts)
	}
	tOpts.validate()
	p := &TaskPool{
		TaskPoolOptions: tOpts,
		qArray:          make([]chan task, tOpts.tQNumber),
		done:            make(chan struct{}),
	}
	for i := 0; i < p.tQNumber; i++ {
		p.qArray[i] = make(chan task, p.tQLen)
	}
	p.start()
	return p
}
func (p *TaskPool) start() {
	for i := 0; i < p.tQPoolSize; i++ {
		p.wg.Add(1)
		workerID := i
		q := p.qArray[workerID%p.tQNumber]
		p.safeRun(workerID, q)
	}
}
func (p *TaskPool) safeRun(workerID int, q chan task) {
	gxruntime.GoSafely(nil, false,
		func() {
			err := p.run(int(workerID), q)
			if err != nil {
				log.Printf("gost/TaskPool.run error: %s", err.Error())
			}
		},
		nil,
	)
}
func (p *TaskPool) run(id int, q chan task) error {
	defer p.wg.Done()
	var (
		ok bool
		t  task
	)
	for {
		select {
		case <-p.done:
			if 0 < len(q) {
				return fmt.Errorf("task worker %d exit now while its task buffer length %d is greater than 0",
					id, len(q))
			}
			return nil
		case t, ok = <-q:
			if ok {
				func() {
					defer func() {
						if r := recover(); r != nil {
							fmt.Fprintf(os.Stderr, "%s goroutine panic: %v\n%s\n",
								time.Now(), r, string(debug.Stack()))
						}
					}()
					t()
				}()
			}
		}
	}
}
func (p *TaskPool) AddTask(t task) (ok bool) {
	idx := atomic.AddUint32(&p.idx, 1)
	id := idx % uint32(p.tQNumber)
	select {
	case <-p.done:
		return false
	default:
		p.qArray[id] <- t
		return true
	}
}
func (p *TaskPool) AddTaskAlways(t task) {
	id := atomic.AddUint32(&p.idx, 1) % uint32(p.tQNumber)
	select {
	case p.qArray[id] <- t:
		return
	default:
		goSafely(t)
	}
}
func (p *TaskPool) AddTaskBalance(t task) {
	length := len(p.qArray)
	for i := 0; i < length/2; i++ {
		select {
		case p.qArray[rand.Intn(length)] <- t:
			return
		default:
			continue
		}
	}
	goSafely(t)
}
func (p *TaskPool) stop() {
	select {
	case <-p.done:
		return
	default:
		p.once.Do(func() {
			close(p.done)
		})
	}
}
func (p *TaskPool) IsClosed() bool {
	select {
	case <-p.done:
		return true
	default:
		return false
	}
}
func (p *TaskPool) Close() {
	p.stop()
	p.wg.Wait()
	for i := range p.qArray {
		close(p.qArray[i])
	}
}
type taskPoolSimple struct {
	work chan task      
	sem  chan struct{}  
	wg sync.WaitGroup
	once sync.Once
	done chan struct{}
}
func NewTaskPoolSimple(size int) GenericTaskPool {
	if size < 1 {
		size = runtime.GOMAXPROCS(-1) * 100
	}
	return &taskPoolSimple{
		work: make(chan task),
		sem:  make(chan struct{}, size),
		done: make(chan struct{}),
	}
}
func (p *taskPoolSimple) AddTask(t task) bool {
	select {
	case <-p.done:
		return false
	default:
	}
	select {
	case <-p.done:
		return false
	case p.work <- t:
	case p.sem <- struct{}{}:
		p.wg.Add(1)
		go p.worker(t)
	}
	return true
}
func (p *taskPoolSimple) AddTaskAlways(t task) {
	select {
	case <-p.done:
		return
	default:
	}
	select {
	case p.work <- t:
		return
	default:
	}
	select {
	case p.work <- t:
	case p.sem <- struct{}{}:
		p.wg.Add(1)
		go p.worker(t)
	default:
		goSafely(t)
	}
}
func (p *taskPoolSimple) worker(t task) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Fprintf(os.Stderr, "%s goroutine panic: %v\n%s\n",
				time.Now(), r, string(debug.Stack()))
		}
		p.wg.Done()
		<-p.sem
	}()
	t()
	for t := range p.work {
		t()
	}
}