package main

import (
	"fmt"
	"time"
)

//创建任务类型
type Task struct {
	f func() error
}

//执行任务
func (t *Task) Execute() {
	t.f()
}

//创建任务对象
func NewTask(f func() error) *Task {
	t := Task{
		f: f,
	}
	return &t
}

//创建任务池
type Pool struct {
	InChannel  chan *Task //任务队列
	JobChannel chan *Task //工作队列
	max        int        //最大消费协程数
}

//创建新的任务池
func NewPool(max int) *Pool {
	p := &Pool{
		InChannel:  make(chan *Task),
		JobChannel: make(chan *Task),
		max:        max,
	}
	return p
}

//消费工作队列
func (p *Pool) work(id int) {
	for task := range p.JobChannel {
		fmt.Printf("%T%v\n", task, id)
		task.Execute()
	}
}

var (
	num int = 1
)

func (p *Pool) Run() {

	//开启多个协程消费工作队列
	for i := 0; i < p.max; i++ {
		go p.work(i)
	}
	fmt.Print("协程写入工作队列start~\n")
	//从任务队列写入工作队列
	for task := range p.InChannel {
		fmt.Println(num)
		num++
		p.JobChannel <- task
	}
	fmt.Print("协程写入工作队列end~\n")
	close(p.JobChannel)

}

//任务入队列
func (p *Pool) TaskInChannel(f *Task) {
	var second = 0
	for second < 3 {
		second++
		p.InChannel <- f
	}
	//遵循是申请谁释放的原则,最好是写入方负责close
	close(p.InChannel)
	fmt.Println("inChan结束~")
}

func main() {

	//创建新的任务,这里只是打印当前的时间戳
	f := NewTask(func() error {
		fmt.Println(time.Now())
		return nil
	})
	//
	创建新的任务池
	p := NewPool(3)
	//
	开启协程创建任务写入任务队列
	go p.TaskInChannel(f)
	//启动
	p.Run()

}