Go 常见并发模式实现(一):调度后台处理任务的作业程序
时间:2022-07-27
本文章向大家介绍Go 常见并发模式实现(一):调度后台处理任务的作业程序,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
关于 Go 语言并发编程基本概念和 Goroutine、Channel 以及锁机制的使用,学院君在 Go 入门教程并发编程章节已经详细介绍过了,这里主要演示通过并发编程在 Go 程序中实现一些常见的并发模式。
首先,我们来看如何开发需要调用后台处理任务的程序,这个程序可能会作为 Cron 作业执行,或者在基于定时任务的云环境(iron.io
)里执行。
我们创建一个 runner
包,在该包中创建一个 job.go
文件,编写对应的作业类实现代码如下:
package runner
import (
"errors"
"os"
"os/signal"
"time"
)
type JobRunner struct {
interrupt chan os.Signal
complete chan error
timeout <-chan time.Time
tasks []func(int)
}
var ErrTimeout = errors.New("received timeout")
var ErrInterrupt = errors.New("received interrupt")
func New(d time.Duration) *JobRunner {
return &JobRunner{
interrupt: make(chan os.Signal, 1),
complete: make(chan error),
timeout: time.After(d),
}
}
func (r *JobRunner) Add(tasks ...func(int)) {
r.tasks = append(r.tasks, tasks...)
}
func (r *JobRunner) Start() error {
// 接收系统中断信号通知
signal.Notify(r.interrupt, os.Interrupt)
go func() {
r.complete <- r.run()
}()
select {
case err := <-r.complete:
return err
case <-r.timeout:
return ErrTimeout
}
}
func (r *JobRunner) run() error {
for id, task := range r.tasks {
if r.gotInterrupt() {
return ErrInterrupt
}
task(id)
}
return nil
}
func (r *JobRunner) gotInterrupt() bool {
select {
case <-r.interrupt:
signal.Stop(r.interrupt)
return true
default:
return false
}
}
上述代码展示了根据调度运行的、无人值守的、面向任务的并发模式程序:调用 Start()
方法启动作业运行器后,会通过协程异步运行作业中的所有后台处理任务,然后通过 select
选择语句判定作业程序是运行结束正常退出、还是收到系统中断信号退出、亦或是超时异常退出,如果正常退出,返回的状态码是 nil,否则是非空的错误值。
这样一来,不管后台处理任务有多少个、耗时多久,都可以做到并发运行,从而提升程序性能和运行效率。
我们可以编写一个入口程序 runner.go
来调用上述调度后台处理任务的作业程序:
package main
import (
"fmt"
"log"
"os"
"test/runner"
"time"
)
const timeout = 3 * time.Second
func main() {
fmt.Println("开始运行...")
// 初始化作业运行器
r := runner.New(timeout)
// 调度三个后台处理任务
r.Add(createTask(), createTask(), createTask())
// 启动作业运行器
if err := r.Start(); err != nil {
switch err {
case runner.ErrTimeout:
log.Println("作业程序因运行超时而终止")
os.Exit(1)
case runner.ErrInterrupt:
log.Println("作业程序因系统发生中断事件而终止")
os.Exit(2)
}
}
}
// 编写一个模拟后台处理任务
func createTask() func(int) {
return func(id int) {
log.Printf("Processor - Task #%d.", id)
time.Sleep(time.Duration(id) * time.Second)
}
}
附:上述示例代码目录结构如下(go.mod
中的 package
名称是 test
):
--go (项目根目录 ~/Development/go)
|--src
|--test
|--runner
|--job.go
|--runner.go
|--go.mod
运行上述代码,输出结果如下:
由于系统超时时间是 3s,而后台处理任务总耗时是3s,因此程序整体运行时间是超过 3s 的,所以显示超时退出,如果我们将系统超时时间延长至 5s,则会正常退出。
(全文完)
- 解决网站静态缓存后WP-PostViews插件不计数的问题
- Haproxy安装部署文档及多配置文件管理方案
- ASM 翻译系列第三十四弹:ASM磁盘组重要属性介绍
- 博客集成Hitokoto·一言经典语句功能
- 博客网页导致电脑CPU飙升的问题解决记录
- 恢复WordPress分类目录的别名链接形式
- 替代crontab,统一定时任务管理系统cronsun简介
- 小网站最简单实用的动静分离优化方案
- Haproxy进阶管理:命令行控制后端节点上下线
- 网站集成打字震动特效JS代码改进版
- Linux基础知识之文件隐藏属性
- Linux系统chmod误操作目录权限恢复方法
- 结合VBS,实现批处理自动以管理员身份执行
- ASM 翻译系列第三十六弹:ACFS磁盘组的重平衡操作
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Yii Framework框架使用PHPExcel组件的方法示例
- thinkphp3.2.3框架动态切换多数据库的方法分析
- 安装docker和docker-compose实例详解
- 如何判断php复选框是否被选中
- php实现的生成排列算法示例
- php多进程应用场景实例详解
- Linux Crontab Shell脚本实现秒级定时任务的办法
- laravel框架实现为 Blade 模板引擎添加新文件扩展名操作示例
- yii框架使用分页的方法分析
- Linux服务器间文件实时同步的实现
- TP3.2.3框架文件上传操作实例详解
- yii2.0框架场景的简单使用示例
- Laravel5.6框架使用CKEditor5相关配置详解
- 怎么在Linux中自定义bash命令提示符
- Hbase入门详解