golang学习笔记之手写一个执行器

来源:互联网 发布:软件客户端界面设计 编辑:程序博客网 时间:2024/06/05 17:00

之前介绍过一个多协程的Parallelize,允许多个协程并发执行任务的函数,今天手写一个控制能力更强的的ruuner,初步实现单个协程处理,后续将继续改进为多协程处理:

package runnerimport ( "errors" "os" "os/signal" "time" )type Runner struct {     // interrupt channel reports a signal from the     // operating system.     interrupt chan os.Signal     // complete channel reports that processing is done.     complete chan error     // timeout reports that time has run out.     timeout <-chan time.Time     // tasks holds a set of functions that are executed     // synchronously in index order.     tasks []func(int)}// ErrTimeout is returned when a value is received on the timeout.var ErrTimeout = errors.New("received timeout")// ErrInterrupt is returned when an event from the OS is received.var ErrInterrupt = errors.New("received interrupt")// New returns a new ready-to-use Runner.func New(d time.Duration) *Runner {    return &Runner{        interrupt: make(chan os.Signal, 1),        complete:  make(chan error),        timeout:   time.After(d),    }}// Add attaches tasks to the Runner. A task is a function that// takes an int ID.func (r *Runner) Add(tasks ...func(int)) {         r.tasks = append(r.tasks, tasks...)}// Start runs all tasks and monitors channel events.func (r *Runner) Start() error {    // We want to receive all interrupt based signals.    // Run the different tasks on a different goroutine.    go func() {        r.complete <- r.run()    }()    select {    // Signaled when processing is done.    case err := <-r.complete:        return err    // Signaled when we run out of time.    case <-r.timeout:        return ErrTimeout       }    }// run executes each registered task.func (r *Runner) run() error {    for id, task := range r.tasks {             // Check for an interrupt signal from the OS.             if r.gotInterrupt() {             return ErrInterrupt            }             // Execute the registered task.        task(id)        }         return nil    }// gotInterrupt verifies if the interrupt signal has been issued.func (r *Runner) gotInterrupt() bool {    select {    // Signaled when an interrupt event is sent.    case <-r.interrupt:    // Stop receiving any further signals.        signal.Stop(r.interrupt)        return true    // Continue running as normal.    default:        return false    }}

注解写的很详细,我简单介绍一下;Runner是一单协程的运行器,里面几个属性interrupt获取os的信号量,complete返回执行结果,timeout设置超时时间,如果超时结束运行,tasks是报错任务的。添加任务通过Add方法:将方法加入到切片中,Start方法启动任务,这里只启动一个协程,后期改进,run方式是具体执行,执行task函数gotInterrupt获取os的消息。
怎样使用呢?看下面:

const timeout  = 2*time.Secondfunc main() {    r := runner.New(timeout)    r.Add(crateTask(),crateTask(),crateTask())    if err := r.Start();  err != nil {        switch err {        case runner.ErrTimeout:            fmt.Println("timeout error")            os.Exit(1)        case runner.ErrInterrupt:            fmt.Println("interrupt error")            os.Exit(2)        }    }    log.Println("end !!!!")}func crateTask()func(int)  {    return func(id int) {        fmt.Println("exec id :",id)        time.Sleep(time.Duration(id)*time.Second)    }}

通过改变timeout时间可以准确的控制任务执行时间,上面2秒的例子,保证每个任务都能运行,执行结果如下:
exec id : 0
exec id : 1
exec id : 2
timeout error
exit status 1
如果改成5s当然能保证执行完成任务:
exec id : 0
exec id : 1
exec id : 2
2017/04/11 09:59:12 end !!!!

0 0
原创粉丝点击