同步适合多个连续执行的,每一步的执行依赖于上一步操作,异步执行则和任务执行顺序无关(如从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. 灵感手环第一步——0.96寸OLED显示实验

    这算是我这个系列的第一篇博客吧.首先要解决的就是屏幕显示问题.我选择了目前新兴起的OLED显示模块. OLED(OrganicLightEmittingDiode),中文译作有机发光二极管,目前被广泛 ...

  2. 側滑回退的layout(相似IOS側滑回退到上一个activity)

    用过apple的同学应该都知道,大多数IOS应用都支持側滑回退,就不具体说明了,直接上图: 作为使用ios的android开发人员来说,我是特别喜欢这个功能的.既然这样,那就在android上也实现这 ...

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

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

  4. Office Web Add-in的技术原理和开发常见问题剖析

    作者:陈希章 发表于 2017年12月20日 我过去发表过一些Office Add-in开发的文章,并且也在不同的场合分享过新的开发模式及其带来的机遇.有不少朋友给我反馈,也讨论到一些常见问题,我这里 ...

  5. DB主从一致性架构优化4种方法

    需求缘起 大部分互联网的业务都是"读多写少"的场景,数据库层面,读性能往往成为瓶颈.如下图:业界通常采用"一主多从,读写分离,冗余多个读库"的数据库架构来提升数 ...

  6. redis 报Operation against a key holding the wrong kind of value警告的解决方法

    WRONGTYPE Operation against a key holding the wrong kind of value github:https://github.com/antirez/ ...

  7. objective-c 开发最简单的UITableView时数据进不去的问题

    今天在使用UITableView时遇到的问题,我在plist文件配置的数据进不去列表,以下是解决方案 问题原因:plist文件root的type配置错误 如上图所示,博主是使用plist文件作为我的沙 ...

  8. 翻译:CREATE DATABASE语句

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

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

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

  10. Grafana4.2安装

    一.文件准备 1.1 文件名称 grafana-4.2.0-1.x86_64.rpm 1.2 下载地址 https://grafana.com/grafana/download 二.工具准备 2.1 ...