Go同步和异步执行多个任务封装
同步适合多个连续执行的,每一步的执行依赖于上一步操作,异步执行则和任务执行顺序无关(如从10个站点抓取数据)
同步执行类RunnerAsync
支持返回超时检测,系统中断检测
错误常量定义,task/err.go
package task import "errors" //超时错误
var ErrTimeout = errors.New("received timeout") //操作系统系统中断错误
var ErrInterrupt = errors.New("received interrupt")
实现代码如下,task/runner_async.go
package task import (
"os"
"os/signal"
"time"
) //同步执行任务
type RunnerAsync struct {
//操作系统的信号检测
interrupt chan os.Signal //记录执行完成的状态
complete chan error //超时检测
timeout <-chan time.Time //保存所有要执行的任务,顺序执行
tasks []func(id int)
} //new一个RunnerAsync对象
func NewRunnerAsync(d time.Duration) *RunnerAsync {
return &RunnerAsync{
interrupt: make(chan os.Signal, 1),
complete: make(chan error),
timeout: time.After(d),
}
} //添加一个任务
func (this *RunnerAsync) Add(tasks ...func(id int)) {
this.tasks = append(this.tasks, tasks...)
} //启动RunnerAsync,监听错误信息
func (this *RunnerAsync) Start() error { //接收操作系统信号
signal.Notify(this.interrupt, os.Interrupt) //执行任务
go func() {
this.complete <- this.Run()
}() select {
//返回执行结果
case err := <-this.complete:
return err //超时返回
case <-this.timeout:
return ErrTimeout
}
} //顺序执行所有的任务
func (this *RunnerAsync) Run() error {
for id, task := range this.tasks {
if this.gotInterrupt() {
return ErrInterrupt
}
//执行任务
task(id)
}
return nil
} //判断是否接收到操作系统中断信号
func (this *RunnerAsync) gotInterrupt() bool {
select {
case <-this.interrupt:
//停止接收别的信号
signal.Stop(this.interrupt)
return true
//正常执行
default:
return false
}
}
使用方法
Add添加一个任务,任务为接收int类型的一个闭包
Start开始执行伤,返回一个error类型,nil为执行完毕, ErrTimeout代表执行超时,ErrInterrupt代表执行被中断(类似Ctrl + C操作)
测试代码
task/runner_async_test.go
package task import (
"fmt"
"os"
"runtime"
"testing"
"time"
) func TestRunnerAsync_Start(t *testing.T) { //开启多核
runtime.GOMAXPROCS(runtime.NumCPU()) //创建runner对象,设置超时时间
runner := NewRunnerAsync(8 * time.Second)
//添加运行的任务
runner.Add(
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
createTaskAsync(),
) fmt.Println("同步执行任务") //开始执行任务
if err := runner.Start(); err != nil {
switch err {
case ErrTimeout:
fmt.Println("执行超时")
os.Exit(1)
case ErrInterrupt:
fmt.Println("任务被中断")
os.Exit(2)
}
} t.Log("执行结束") } //创建要执行的任务
func createTaskAsync() func(id int) {
return func(id int) {
fmt.Printf("正在执行%v个任务\n", id)
//模拟任务执行,sleep两秒
//time.Sleep(1 * time.Second)
}
}
执行结果
同步执行任务
正在执行0个任务
正在执行1个任务
正在执行2个任务
正在执行3个任务
正在执行4个任务
正在执行5个任务
正在执行6个任务
正在执行7个任务
正在执行8个任务
正在执行9个任务
正在执行10个任务
正在执行11个任务
正在执行12个任务
异步执行类Runner
支持返回超时检测,系统中断检测
实现代码如下,task/runner.go
package task import (
"os"
"time"
"os/signal"
"sync"
) //异步执行任务
type Runner struct {
//操作系统的信号检测
interrupt chan os.Signal //记录执行完成的状态
complete chan error //超时检测
timeout <-chan time.Time //保存所有要执行的任务,顺序执行
tasks []func(id int) error waitGroup sync.WaitGroup lock sync.Mutex errs []error
} //new一个Runner对象
func NewRunner(d time.Duration) *Runner {
return &Runner{
interrupt: make(chan os.Signal, 1),
complete: make(chan error),
timeout: time.After(d),
waitGroup: sync.WaitGroup{},
lock: sync.Mutex{},
}
} //添加一个任务
func (this *Runner) Add(tasks ...func(id int) error) {
this.tasks = append(this.tasks, tasks...)
} //启动Runner,监听错误信息
func (this *Runner) Start() error { //接收操作系统信号
signal.Notify(this.interrupt, os.Interrupt) //并发执行任务
go func() {
this.complete <- this.Run()
}() select {
//返回执行结果
case err := <-this.complete:
return err
//超时返回
case <-this.timeout:
return ErrTimeout
}
} //异步执行所有的任务
func (this *Runner) Run() error {
for id, task := range this.tasks {
if this.gotInterrupt() {
return ErrInterrupt
} this.waitGroup.Add(1)
go func(id int) {
this.lock.Lock() //执行任务
err := task(id)
//加锁保存到结果集中
this.errs = append(this.errs, err) this.lock.Unlock()
this.waitGroup.Done()
}(id)
}
this.waitGroup.Wait() return nil
} //判断是否接收到操作系统中断信号
func (this *Runner) gotInterrupt() bool {
select {
case <-this.interrupt:
//停止接收别的信号
signal.Stop(this.interrupt)
return true
//正常执行
default:
return false
}
} //获取执行完的error
func (this *Runner) GetErrs() []error {
return this.errs
}
使用方法
Add添加一个任务,任务为接收int类型,返回类型error的一个闭包
Start开始执行伤,返回一个error类型,nil为执行完毕, ErrTimeout代表执行超时,ErrInterrupt代表执行被中断(类似Ctrl + C操作)
getErrs获取所有的任务执行结果
测试示例代码
task/runner_test.go
package task import (
"testing"
"time"
"fmt"
"os"
"runtime"
) func TestRunner_Start(t *testing.T) {
//开启多核心
runtime.GOMAXPROCS(runtime.NumCPU()) //创建runner对象,设置超时时间
runner := NewRunner(18 * time.Second)
//添加运行的任务
runner.Add(
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
createTask(),
) fmt.Println("异步执行任务") //开始执行任务
if err := runner.Start(); err != nil {
switch err {
case ErrTimeout:
fmt.Println("执行超时")
os.Exit(1)
case ErrInterrupt:
fmt.Println("任务被中断")
os.Exit(2)
}
} t.Log("执行结束") t.Log(runner.GetErrs()) } //创建要执行的任务
func createTask() func(id int) error {
return func(id int) error {
fmt.Printf("正在执行%v个任务\n", id)
//模拟任务执行,sleep
//time.Sleep(1 * time.Second)
return nil
}
}
执行结果
异步执行任务
正在执行2个任务
正在执行1个任务
正在执行4个任务
正在执行3个任务
正在执行6个任务
正在执行5个任务
正在执行9个任务
正在执行7个任务
正在执行10个任务
正在执行13个任务
正在执行8个任务
正在执行11个任务
正在执行12个任务
正在执行0个任务
Go同步和异步执行多个任务封装的更多相关文章
- Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表,以及同步和异步执行模式)
系列文章导航 Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表) Adobe AIR中使用Flex连接Sqlite数据库(2)(添加,删除,修改以及语句参数) Adobe ...
- ajax同步、异步执行简单理解与证明
此理解范例代码来自前几篇随笔! 首先我们来先了解下AJAX: Ajax:全称“Asynchronous Javascript and XML”(异步Javascript和XML),他是由Javascr ...
- ASP.NET mvc4 Controllder 同步还是异步
从抽象类Controller 的定义可以看出他 同时实现了 IAsyncController, IController public abstract class Controller : Contr ...
- day37 GIL、同步、异步、进程池、线程池、回调函数
1.GIL 定义: GIL:全局解释器锁(Global Interpreter Lock) 全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码 为什么需要全局解释器锁 在我们进行代码编写时,实 ...
- thread.join 从异步执行变成同步
Java的线程模型为我们提供了更好的解决方案,这就是join方法.在前面已经讨论过,join的功能就是使用线程 从异步执行变成同步执行 当线程变成同步执行后,就和从普通的方法中得到返回数据没有什么区别 ...
- js文件引用方式及其同步执行与异步执行
详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp74 任何以appendChild(scriptNode) 的方式引入 ...
- 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
聊聊同步.异步和回调 同步,异步,回调,我们傻傻分不清楚, 有一天,你找到公司刚来的程序员小T,跟他说:“我们要加个需求,你放下手里的事情优先支持,我会一直等你做完再离开”.小T微笑着答应了,眼角却滑 ...
- js同步、异步、回调的执行顺序以及闭包的理解
首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...
- 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)
首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...
随机推荐
- Django模型中value函数运用
values(*fields) 这个方法返回的是ValuesQuerySet,是QuerySet 的子类,也就是说,你可以用QuerySet里的方法. 需要注意的是,返回的不是list,不要直接当li ...
- 》》QQ-注册
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- mvc 中Range中max和min值晚绑定
对于Attribute : Range(min,max)的min和max必须在用的时候给,但是需求有时须要把这两个值存db.动态取出的.这时就须要razor帮忙了: @Html.TextBoxFor( ...
- linux shell 推断文件或目录是否真的存在
#推断文件或目录是否存在 filepath=/data/test.txt folderpath=/data/qtech #推断文件是否存在 if [ -f "$file" ] th ...
- 基于FPGA的图像显示
基于FPGA的图像显示 作者:lee神 这几天一直在调试FPGA的图像显示系统,今天终于成功,图像不在闪烁,也不再边框缺失. 基于FPGA的图像处理的第一课应该是基于FPGA的图像显示,只有图像正常显 ...
- 注册Azure AD 应用程序
作者:陈希章 发表于2017年3月22日 在此前的文章中,我给大家介绍了分别用Graph 浏览器以及第三方工具(POSTMAN)快速体验Microsoft Graph的功能,其中有一个重要的环节就是, ...
- 快看Sample代码,速学Swift语言(1)-语法速览
Swift是苹果推出的一个比较新的语言,它除了借鉴语言如C#.Java等内容外,好像还采用了很多JavaScript脚本里面的一些脚本语法,用起来感觉非常棒,作为一个使用C#多年的技术控,对这种比较超 ...
- MPSOC之7——开发流程uramdisk
用petalinux的预编译目录里有rootfs文件,选择rootfs.tar.gz作为初始输入. 1.原始文件-->uramdisk 1.1 解压原始rootfs.tar.gz,得到若干文件 ...
- Struts2框架(3)---Action类的3种书写方式
Action类的3种书写方式 本文主要写有关写Action类的3种书写方式: (1)第一种 Action可以是POJO (简单模型对象) 不需要继承任何父类 也不需要实现任何接口 (2)实现Acti ...
- 507. Perfect Number
We define the Perfect Number is a positive integer that is equal to the sum of all its positive divi ...