golang并发模式runner

1 runner/runner.go

package runner

import (
        "errors"
        "os"
        "os/signal"
        "time"
)
type Runner struct {
        interrupt chan os.Signal   //接收信号的通道
        complete chan error        //接收完成的通道
        timeout <-chan time.Time   //接收超时的通道
        tasks []func(int)                    //任务数组,保存的是函数,函数作为一个元素使用。
}
//统一错误
var ErrTimeout = errors.New("received timeout")
var ErrInterrupt = errors.New("received interrupt")
//
func New(d time.Duration) *Runner {
        return &Runner {
                interrupt:make(chan os.Signal, 1), //创建信号通道
                complete: make(chan error),        //任务完成通道
                timeout:time.After(d),                   //返回一个时间通道,该通道在无操作时,d时间后激发超时
        }
}
func (r *Runner) Add(tasks ...func(int)) {  //添加任务,可以多参数方式,可以添加多个。
        r.tasks = append(r.tasks,tasks...)      //切片可以这样使用。数组不可以使用
}
func (r* Runner) Start() error {
        signal.Notify(r.interrupt, os.Interrupt) //信号接收通知
        go func(){
                r.complete <- r.run()   //启动另外一个线程,把所有任务都运行一遍,把错误返回,1, nil正常,2 ErrInterrupt
        }()
        select { //如果有通道接收到消息,就运行。如果没有通道接收到消息就阻塞。此时主线程就阻塞,等待信号到来。
                case err := <-r.complete:   //等待到任务完成
                        return err
                case <-r.timeout:   //等待到操作
                        return ErrTimeout       
        }
}
func (r *Runner) run() error {
        for id, task := range r.tasks {   //遍历数组,运行各个函数
                if r.gotInterrupt() {
                        return ErrInterrupt    //接收到CTRL-C信号
                }
                task(id)
        }
        return nil   //如果无误,则返回nil 
}
func (r *Runner) gotInterrupt() bool {
        select {
                case <- r.interrupt:   //接收到os.Interrupt
                        signal.Stop(r.interrupt)  //停止接收以后的信号
                        return true
                default:
                        return false    
        }

}

2 main/main.go

package main 
import (
        "ch7/runner"
        "log"
        "time"
        "os"
)
const timeout = 5 * time.Second
func main() {
        log.Println("Starting work.")
        r := runner.New(timeout)
        r.Add(createTask(), createTask(),createTask())
        if err := r.Start(); err != nil {
                switch err {
                        case runner.ErrTimeout:
                                log.Println("Terminating due to timeout.")
                                os.Exit(1)
                        case runner.ErrInterrupt:
                                log.Println("Terminating due to interrupt.")
                                os.Exit(2)
                  }
        }
        log.Println("Process ended.")
}
func createTask() func(int){
        return func(id int){
                log.Printf("Processor - Task #%d.", id)
                time.Sleep(time.Duration(id)*time.Second)
        }
}

猜你喜欢

转载自blog.csdn.net/haolifengwang/article/details/80402403