同步适合多个连续执行的,每一步的执行依赖于上一步操作,异步执行则和任务执行顺序无关(如从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同步和异步执行多个任务封装的更多相关文章

  1. Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表,以及同步和异步执行模式)

    系列文章导航 Adobe AIR中使用Flex连接Sqlite数据库(1)(创建数据库和表) Adobe AIR中使用Flex连接Sqlite数据库(2)(添加,删除,修改以及语句参数) Adobe ...

  2. ajax同步、异步执行简单理解与证明

    此理解范例代码来自前几篇随笔! 首先我们来先了解下AJAX: Ajax:全称“Asynchronous Javascript and XML”(异步Javascript和XML),他是由Javascr ...

  3. ASP.NET mvc4 Controllder 同步还是异步

    从抽象类Controller 的定义可以看出他 同时实现了 IAsyncController, IController public abstract class Controller : Contr ...

  4. day37 GIL、同步、异步、进程池、线程池、回调函数

    1.GIL 定义: GIL:全局解释器锁(Global Interpreter Lock) 全局解释器锁是一种互斥锁,其锁住的代码是全局解释器中的代码 为什么需要全局解释器锁 在我们进行代码编写时,实 ...

  5. thread.join 从异步执行变成同步

    Java的线程模型为我们提供了更好的解决方案,这就是join方法.在前面已经讨论过,join的功能就是使用线程 从异步执行变成同步执行 当线程变成同步执行后,就和从普通的方法中得到返回数据没有什么区别 ...

  6. js文件引用方式及其同步执行与异步执行

    详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp74   任何以appendChild(scriptNode) 的方式引入 ...

  7. 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析

    聊聊同步.异步和回调 同步,异步,回调,我们傻傻分不清楚, 有一天,你找到公司刚来的程序员小T,跟他说:“我们要加个需求,你放下手里的事情优先支持,我会一直等你做完再离开”.小T微笑着答应了,眼角却滑 ...

  8. js同步、异步、回调的执行顺序以及闭包的理解

    首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...

  9. 深入理解 JS 引擎执行机制(同步执行、异步执行以及同步中的异步执行)

    首先明确两点: 1.JS 执行机制是单线程. 2.JS的Event loop是JS的执行机制,深入了解Event loop,就等于深入了解JS引擎的执行. 单线程执行带来什么问题? 在JS执行中都是单 ...

随机推荐

  1. mac cocos2dx android

    1. localhost:proj.android mxhd4$ ./build_native.sh 报错 Compile++ thumb  : cocosdenshion_static <= ...

  2. Android Static分析

    1.static的变量或者方法会放在内存的一个方法区内 2.static变量会在该变量所属的类从内存中释放掉之后. 才会释放掉而类释放的条件是非常苛刻的. 必需要该类相应的全部对象被释放掉. 同一时候 ...

  3. iOS日历中给一个事件加入多个提醒

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 假设认为写的不好请多提意见,假设认为不错请多多支持点赞.谢谢! hopy ;) iOS自带的日历应用中,我们最多仅仅能给一个事件设置2个提醒, ...

  4. Hadoop之SequenceFile

    Hadoop序列化文件SequenceFile能够用于解决大量小文件(所谓小文件:泛指小于black大小的文件)问题,SequenceFile是Hadoop API提供的一种二进制文件支持.这样的二进 ...

  5. 2016年7月微软MVP申请開始了!

    2016年7月微软MVP申请開始了! CSDN与微软合作,长期为用户提供申请"微软最有价值专家"的平台.希望有兴趣.资历的朋友以及正在朝这个方向努力的朋友能够积极參与. 2016年 ...

  6. Simple prefix compression

    题目 看懂题目的意思 直接模拟就能够了 好像不用递归就能够了. . 尽管这周学的是递归 还是偷了一些懒  直接模拟 在说这个题目的意思 本来能够写的非常清楚的下标 题目非要把两个字符串的表示方法写的这 ...

  7. 原生JS与jQuery操作DOM对比

    一.创建元素节点 1.1 原生JS创建元素节点 document.createElement("p"); 1.2 jQuery创建元素节点 $('<p></p&g ...

  8. Office Add-in 设计规范与最佳实践

    作者:陈希章 发表于 2017年8月6日 引子 离上一篇Office Add-in的文章已经过去了一段时间,期间有去年Office 365 Asia Devday & Hackathon的二等 ...

  9. 如何在Gulp中提高Browserify的打包速度

    使用Browserify打包js时如果项目变得越来越大,编译时间就会相应变得越来越长.使用官方的插件watchify是个比较有效的提高速度方案. 提速原理 watchify的用法和gulp的watch ...

  10. Django的Models(二)映射关系

    关系分为三种: 一对一 :user2 = models.OneToOneField("UserInfo") 一对多:user = models.ForeignKey("U ...