Golang 并发 - runner [Part One]

本文介绍了Golang中的runner包,主要用于通过channel监控程序执行时间并能终止程序。适用场景包括调度后台处理任务,特别是在cron作业或定时任务云环境中。文章深入解析了runner包的源码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Golang 并发 - runner

runner包简介

  1. 用途
    • 使用channel监视程序的执行时间
    • 终止程序
  2. 使用场景
    • 调度后台处理任务的程序(该任务可能作为cron作业执行,or在基于定时任务的云环境里执行)

源码解析

// runner 包管理处理任务的运行与生命周期
package runner

import (
	"errors"
	"os"
	"os/signal"
	"time"
)

// 声明Runner结构,Runner的任务有
//1. 在给定的超时时间内执行一组任务
//2. 在操作系统发送中断信号时结束这些任务
type Runner struct {
	// interrupt channel 接收从操作系统发来的信号
	interruput chan os.Signal
	
	// complete channel 报告处理任务已完成
	complete chan error
	
	// timeout chanel 报告处理任务已超时 
	timeout <-chan time.Time

	// tasks 持有一组以索引顺序执行的任务函数
	tasks []func(int)
}

// ErrTimeout 是在任务超时时返回的错误
var ErrTimeout = errors.New("received timeout")
 
// ErrInterrupt 是在接收到操作系统信号时返回的错误
var ErrInterrupt = errors.New("received interrupt")

// 工厂函数, 返回一个Runner类型的指针
func New(d time.Duration) *Runner {
	// 分别初始化channel中的各个通道值
	return &Runner{
		 // 将interrupt 初始化为缓存为1的channel,保证至少能接收一个来自语言运行时的os.Signal,
		 // 确保语言运行时发送这个事件的时候不会被阻塞,如果goroutine没有准备好接收数据,
		 // 数据将被抛弃。比如用户在狂按ctrl+C时,程序只有在准备好时接收事件,其余将被抛弃。
		 interrupt: make(chan os.Signal, 1),
		 
		 // complete 初始化为一个无缓存的channel, 当执行任务的goroutine完成时,会向这个通道发送一个error值或者nil值
		 // 一旦 main接收了这个error值, goroutine 就可以安全地终止了
         complete: make(chan error),
		
		 // time.After()是time包的内置函数,返回一个time.Time类型的channel值
		 // 语言运行时会在指定的 duration 时间到期之后,向这个channel发一个 time.Time 值。
         timeout: time.After(d),
    }
 }

// 与Runner关联的方法
// Add 将一个任务添加到Runner中,这个任务是一个接收一个int参数,不返回任何参数的函数
func (r *Runner) Add(tasks ...func(int)) {
    r.tasks = append(r.tasks, tasks...)
}

//  run 执行每一个已注册的任务
func (r *Runner) run() error {
	for id, task := range r.tasks {
		if r.gotInterrupt() {
			 return ErrInterrupt
		}
		// 执行已注册的任务
		task(id)
 	}
 	return nil
	}
}

// gotInterrupt 方法验证是否接受到了中断信号
func (r *Runner) gotInterrupt() bool  {
	select {
		// 接收到中断信号后,停止接收后续任何信号
		case <- r.interrupt:
			signal.Stop(r.interrrupt)
			return true
		default:
			return false
	}
}

// Start 执行所有任务,同时监听channel event
func (r *Runner) Start() error {
	// 接收所有中断信号
	signal.Notify(r.interrupt, os.Interrupt)

	// 将任务放在不同的goroutine中执行
	go func() {
		r.complete <- r.run()
	}()
	select {
		// 任务正常结束时,发出信号
		case err := <-r.complete:
			return err
		// 任务超时时,发出信号
		case <- r.timeout:
			return ErrTimeout
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值