Go语言实战–runner

代码

runner.go

// Example is provided with help by Gabriel Aszalos.
// Package runner manages the running and lifetime of a process.
package runnerimport ("errors""os""os/signal""time"
)// Runner runs a set of tasks within a given timeout and can be
// shut down on an operating system interrupt.
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 channel.
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.signal.Notify(r.interrupt, os.Interrupt)// 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}
}

main.go

// This sample program demonstrates how to use a channel to
// monitor the amount of time the program is running and terminate
// the program if it runs too long.
package mainimport ("log""os""time""github.com/goinaction/code/chapter7/patterns/runner"
)// timeout is the number of second the program has to finish.
const timeout = 3 * time.Second// main is the entry point for the program.
func main() {log.Println("Starting work.")// Create a new timer value for this run.r := runner.New(timeout)// Add the tasks to be run.r.Add(createTask(), createTask(), createTask())// Run the tasks and handle the result.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.")
}// createTask returns an example task that sleeps for the specified
// number of seconds based on the id.
func createTask() func(int) {return func(id int) {log.Printf("Processor - Task #%d.", id)time.Sleep(time.Duration(id) * time.Second)}
}

代码分析

runner包:

使用通道监视程序的执行时间,当程序运行时间太长时,可以使用runner包中止程序。

type Runner struct {interrupt chan os.Signalcomplete chan errortimeout <-chan time.Timetasks []func(int)
}
Runner结构体:

定义了

1 通过channel接收来自操作系统发送的信号

2 任务完成的信号

3 超时信号

4 任务切片

New
func New(d time.Duration) *Runner {return &Runner{interrupt: make(chan os.Signal, 1),complete:  make(chan error),timeout:   time.After(d),}
}

通过New返回一个新的Runner:

complete:

当执行任务的goroutine完成时,会向这个通道发送一个error类型的值或者nil值。之后就会等待main函数接收这个值。一旦main接收了这个error值,goroutine就可以安全地终止了

time.After(d):

func After(d Duration) <-chan Time {return NewTimer(d).C
}
Add
func (r *Runner) Add(tasks ...func(int)) {r.tasks = append(r.tasks, tasks...)
}

Add方法,这个方法接收一个名为 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.interrupt)return truedefault:return false}
}

其中signal.Stop(r.interrupt):

func Stop(c chan<- os.Signal)

Stop函数让signal包停止向c转发信号。它会取消之前使用c调用的所有Notify的效果。当Stop返回后,会保证c不再接收到任何信号。

start
func (r *Runner) Start() error {signal.Notify(r.interrupt, os.Interrupt)go func() {r.complete <- r.run()}()select {case err := <-r.complete:return errcase <-r.timeout:return ErrTimeout}
}

实现了程序的主流程:

func Notify(c chan<- os.Signal, sig ...os.Signal)

Notify函数让signal包将输入信号转发到c。如果没有列出要传递的信号,会将所有输入信号传递到c;否则只传递列出的输入信号。

signal包不会为了向c发送信息而阻塞(就是说如果发送时c阻塞了,signal包会直接放弃):调用者应该保证c有足够的缓存空间可以跟上期望的信号频率。对使用单一信号用于通知的通道,缓存为1就足够了。

main.go

r.Add(createTask(), createTask(), createTask())
func createTask() func(int) {return func(id int) {log.Printf("Processor - Task #%d.", id)time.Sleep(time.Duration(id) * time.Second)}
}

Go语言实战--学习笔记--runner相关推荐

  1. R语言实战学习笔记-高级数据管理

    本文将从以下几个方面介绍R语言中的数据管理,1.数据处理函数 2.控制流 3.用户自定义函数 4.整合和重构 1.数据的处理函数 #实例 x<-c(1,2,3,4,5,6,7,8,9) y< ...

  2. “物联网开发实战”学习笔记-(四)智能音箱制作和语音控制

    "物联网开发实战"学习笔记-(四)智能音箱制作和语音控制 这次来造一个属于自己的智能音箱,这里详细介绍了智能音箱的语音控制的实现. 智能音箱的技术架构 智能音箱主要涉及拾音.前端信 ...

  3. R语言可视化学习笔记之相关矩阵可视化包ggcorrplot

    本文转载自"R语言中文社区",己获授权. 作者简介Introduction taoyan:伪码农,R语言爱好者,爱开源. 个人博客: https://ytlogos.github. ...

  4. R语言可视化学习笔记之ggridges包绘制山峦图

    作者:严涛 浙江大学作物遗传育种在读研究生(生物信息学方向)伪码农,R语言爱好者,爱开源. 严涛老师的绘图教程还有: gganimate |诺奖文章里面的动图绘制教程来了!! ggplot2学习笔记之 ...

  5. Java 8 实战学习笔记

    Java 8 实战学习笔记 @(JAVASE)[java8, 实战, lambda] 文章目录 Java 8 实战学习笔记 参考内容 Lambda表达式 Lambda环绕执行模式(抽离步骤) 原始代码 ...

  6. Linux性能优化实战学习笔记:第四十六讲=====实战分析

    Linux性能优化实战学习笔记:第四十六讲 一.上节回顾 不知不觉,我们已经学完了整个专栏的四大基础模块,即 CPU.内存.文件系统和磁盘 I/O.以及网络的性能分析和优化.相信你已经掌握了这些基础模 ...

  7. “物联网开发实战”学习笔记-(五)根据土壤湿度、环境温湿度和光照强度自动浇花

    "物联网开发实战"学习笔记-(五)根据土壤湿度.环境温湿度和光照强度自动浇花 研究场景需求 自动浇花这个场景,很明显是为了自动控制水泵,及时给植物补充水分.同时用户的目的并不只是浇 ...

  8. Go语言实战读书笔记

    2019独角兽企业重金招聘Python工程师标准>>> Go语言实战读书笔记 第二章 通道(channel).映射(map)和切片(slice)是引用类型.引用类型的对象需要使用ma ...

  9. c语言课程笔记格式,C语言课程学习笔记.docx

    C语言课程学习笔记 C语言基础语言排行榜C--java--objective-C进制:进制:进位机制.用普通的话讲,应该为人为的定义一种度量来标识一样东西.计算机常用的进制有:十进制.二进制.八进制和 ...

  10. r语言electricity数据集_R语言实战学习

    <R语言实战>中文电子版 提取码:lx35 已经学习打卡R语言22天了,可以说是初窥真容--基本了解R的数据和函数:作为程序语言,就是要多练习,多领悟,在实战中发现问题并解决问题. 所以, ...

最新文章

  1. 计算机病毒洛,蓝狐动漫《百变机兽》中未完的战争,蓝毒兽原来是电脑病毒?...
  2. java空指针避坑指南
  3. 如何用智能有效感知城市?城市大脑三大AI产品来了
  4. kafka学习汇总系列(一)kafka概述
  5. 没人性!让我们这么早来上班
  6. 用计算机制作动画,如何使用制作工具制作一个简单的Flash动画-电脑自学网
  7. python随机选人程序_python: 随机选择
  8. 新浪邮箱文件下载php,免费邮箱大全收集-国内篇
  9. 桥接模式 和 中继模式
  10. lvds输入悬空_低压差分信号LVDS学习笔记-模拟/电源-与非网
  11. CentOS 7 systemd添加自定义系统服务
  12. Git reset --hard commit_id 和 git reset --soft commit_id
  13. Qt实现word文档转html
  14. AI发展的桎梏在于理解能力?大咖开出的十一条建议「AI前沿」
  15. oracle(知识点速查)
  16. 与或非门——python逻辑电路
  17. 移动端实时音视频直播技术详解(一):开篇
  18. 基于springboot的工资管理系统
  19. 洛谷 P1319 压缩技术 C/C++
  20. libs与External Libraries

热门文章

  1. SSH进阶(2)——用Struts拦截器实现登陆限制
  2. 查看计算机显卡驱动版本,电脑怎么更新显卡驱动?如何查看驱动是否正常
  3. 【深入理解Java原理】ThreadLocal
  4. C#txt文本分割器
  5. windows 下安装redis
  6. ACDsee_14中文许可证秘钥
  7. editplus3 关联鼠标右键
  8. 翻译记忆库 Translation Memory
  9. 同义句转换在线翻译器的软件
  10. .net 6简单使用NPOI 读取 Excel 案例+流程