func (c *Scheduler) Set(chCancel <-chan struct{}, t time.Time, task func(time.Time)) error {
	if t.IsZero() {
		return ErrInvalidTime
	} else if task == nil {
		return ErrInvalidTask
	}
	select {
	case <-c.chClose:
		return ErrClosed
	case <-chCancel:
		return ErrTaskCancelled
	case c.chJob <- job{chCancel: chCancel, t: t, task: task}:
		return nil
	}
}
Set enqueue new task to scheduler heap queue.
task will be cancelled by closing chCancel. chCancel == nil is acceptable.
package htask
import (
	"errors"
	"sync"
	"time"
)
var (
	ErrClosed         = errors.New("scheduler is already closed")
	ErrInvalidWorkers = errors.New("workers must be more than 0")
	ErrInvalidTime    = errors.New("time is invalid zero time")
	ErrInvalidTask    = errors.New("task must not be nil")
	ErrTaskCancelled  = errors.New("task cancelled")
)
type job struct {
	chCancel <-chan struct{}
	t        time.Time
	task     func(time.Time)
}
type Scheduler struct {
	chClose   chan struct{}
	wg        *sync.WaitGroup
	chJob     chan job
	chWork    chan job
	chFin     chan struct{}
	chWorkers chan int
	wNum      int
}
func NewScheduler(wg *sync.WaitGroup, workers int) *Scheduler {
	if workers < 0 {
		workers = 0
	}
	c := &Scheduler{
		chClose:   make(chan struct{}),
		wg:        wg,
		chJob:     make(chan job),
		chWork:    make(chan job),
		chFin:     make(chan struct{}),
		chWorkers: make(chan int),
	}
	for i := 0; i < workers; i++ {
		wg.Add(1)
		go c.worker(wg)
		c.wNum++
	}
	wg.Add(1)
	go c.scheduler(wg, workers)
	return c
}