同步适合多个连续执行的,每一步的执行依赖于上一步操作,异步执行则和任务执行顺序无关(如从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. iscroll使用之页面卡顿问题

    最近在开发项目时,遇到一个问题,使用iscroll实现的页面滚动,测试时发现在chrome浏览器中的模拟移动设备页面不能平滑滚动,有卡顿现象,在android手机端也有同样的问题. 在github上搜 ...

  2. SpringMVC+Mybatis架构中的问题记录

    2014/08/16 记录 今天遇到个问题.折腾了我大约4个小时,好坑啊由于之前没遇到过 我的包是这么分的:com.project名.模块名.service.impl     在spring 配置这个 ...

  3. 5. Effective Java 第三版——使用依赖注入取代硬连接资源

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  4. TP3.2.3 接入银联支付

    TP3.2.3 接入银联支付 项目接入银联支付的过程, 在此记录下,希望能帮助开发盆友平坑. 银联SKD链接:https://open.unionpay.com/ajweb/product/newPr ...

  5. Ubuntu 16.06 安装拼音输入法 设置双拼

    一不小心把Ubuntu删东西删坏了 呜- 刚好跟可恶的  下载 文件夹告别了 现在百度上的相关教程多多少少有些问题,多数过时了. +++++++++++++++++++++说正事专用分隔符++++++ ...

  6. Mybatis中的模糊查询

    今天下午做的一个功能,要用到模糊查询,字段是description,刚开始我的写法用的是sql中的模糊查询语句, 但是这个有问题,只有将字段的全部值传入其中,才能查询,所以不是迷糊查询. 后来经过搜索 ...

  7. python运算符优先级问题

    附上 对于or与and运算 其一, 在不加括号时候, and优先级大于or 其二, x or y 的值只可能是x或y. x为真就是x, x为假就是y 第三, x and y 的值只可能是x或y. x为 ...

  8. linux定时器crontab

    linux定时器crontab用法: 1.基本格式 : * * * * * command 分 时 日 月 周 命令 第1列表示分钟1-59 每分钟用*或者 */1表示 第2列表示小时1-23(0表示 ...

  9. asp.net mvc 下拉列表

    第一步:新建一个格式化下拉列表的公共类文件 using System; using System.Collections; using System.Collections.Generic; usin ...

  10. iOS 工程默认只允许竖屏,在单独界面进行横竖转换,屏幕旋转

    只含有 .关于横竖屏的代码 #import "InspectionReportViewController.h" #define SCREEN_WIDTH ([UIScreen m ...