同步适合多个连续执行的,每一步的执行依赖于上一步操作,异步执行则和任务执行顺序无关(如从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. iOS 读书笔记-国际化

    吐槽一下:国际化-我想说学习的这个project好痛苦. 也许是百度的原因,总是不能找到自己想要东西. 找到的内容不是不具体就是时间有点久了.让我这种小白非常头痛. 以下记录一下整个过程. 国际化是什 ...

  2. POJ 1469(裸二分匹配)

    COURSES Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 18993   Accepted: 7486 Descript ...

  3. Xcode 7.0 官方免费的真机开发

    Xcode 7.0 官方免费的真机开发 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转 ...

  4. [Phonegap+Sencha Touch] 移动开发26 Android下的sencha touch程序,转屏时,Ext.Viewport不能触发orientationchange事件的解决的方法

    Sencha touch 2.4.2 已经解决问题了. 比方你为Ext.Viewport的orientationchange事件加入了一个监听方法: Ext.Viewport.on('orientat ...

  5. XML文档读取-DOM4j

    JAXP是sun公司官方提供的java解析工具包,但很多其他企业和机构也都开发了自己的xml解析工具,甚至比JAXP更加优秀,比如DOM4J. Dom4j是一个简单.灵活的开放源代码的库.Dom4j是 ...

  6. AOP入门(转)

    本文转自http://www.cnblogs.com/yanbincn/archive/2012/06/01/2530377.html Aspect Oriented Programming  面向切 ...

  7. 转:iOS开发之多种Cell高度自适应实现方案的UI流畅度分析

    本篇博客的主题是关于UI操作流畅度优化的一篇博客,我们以TableView中填充多个根据内容自适应高度的Cell来作为本篇博客的使用场景.当然Cell高度的自适应网上的解决方案是铺天盖地呢,今天我们的 ...

  8. dropout理解:1神带9坑

    Dropout是深度学习中防止过拟合的一项非常常见的技术,是hinton大神在12年提出的一篇论文里所采用的方法.有传言hinton大神的数学功底不是很好,所以他所提出的想法背后的数学原理并不是很复杂 ...

  9. Java 银行家算法

    实验存档,代码特别烂.. 测试.java package operating.test; import operating.entity.bank.Bank; import operating.ent ...

  10. kafka副本机制之数据可靠性

    一.概述 为了提升集群的HA,Kafka从0.8版本开始引入了副本(Replica)机制,增加副本机制后,每个副本可以有多个副本,针对每个分区,都会从副本集(Assigned Replica,AR)中 ...