go 并发处理脚本
时间:2022-05-03
本文章向大家介绍go 并发处理脚本,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
并发处理脚本
最近经常涉及到脚本的编写。本身项目数据量较大,所以经常编写的脚本需要高并发,干脆就提取出来。
如果有地方用到,只需要实现接口即可。
谨以此文抛砖引玉,不喜勿喷
package script
import (
"fmt"
"time"
"errors"
"flag"
"pigcome/utils"
)
// 实现此接口即可
type model interface {
// 每个goroutine运行的函数
RunOne(id int64) (params []int64, errInfos map[int64]string, err error)
// 最后收集到结果后的处理函数
HandleResult(res Result)
}
type RunParam struct {
Start int64 //起始ID
End int64 //结束ID
Step int //同时进行的goroutine数目
Ids []int64 //自定义IDs
Deadline time.Duration //goroutine超时限制
}
type ResultType int
const (
_ ResultType = iota
Success
Panic
Timeout
Error
)
type Result struct {
Type ResultType //结果类型
ID int64 //每个goroutine的ID
Ress []int64 //结果的参数(自定义)
ErrInfos map[int64]string //runOne函数自定义的错误信息
ErrInfo error //整个goroutine的错误信息
}
func Run(params *RunParam, m model) (err error) {
beginAt := time.Now()
err = CheckParams(params)
if err != nil {
return
}
// 1000并没有什么特殊意义,只是为了有缓冲,提高速度
ch := make(chan Result, 1000)
// 令牌,只有持有令牌才能运行,为了控制goroutine同时进行的数目
token := make(chan struct{}, params.Step)
// 以此判断结果是否都处理完成
done := make(chan struct{})
go collectResult(params, ch, done, m)
if len(params.Ids) > 0 {
for _, id := range params.Ids {
token <- struct{}{}
go runOne(params, ch, m, token, id)
}
} else {
for id := params.Start; id < params.End; id++ {
token <- struct{}{}
go runOne(params, ch, m, token, id)
}
}
<-done
since := time.Since(beginAt)
utils.PrintlnColorful(utils.Yellow, "耗时:", since.String())
return
}
func collectResult(params *RunParam, ch chan Result, done chan struct{}, m model) {
var finishCount, count int64
idsLength := len(params.Ids)
if idsLength > 0 {
count = int64(idsLength)
} else {
count = params.End - params.Start
}
for {
result := <-ch
m.HandleResult(result)
finishCount++
if result.ErrInfo != nil {
utils.PrintfColorful(utils.Red, "%d: %+vn", finishCount, result)
}
if finishCount >= count {
done <- struct{}{}
return
}
}
}
func runOne(params *RunParam, ch chan Result, m model, token chan struct{}, id int64) {
defer func() {
<-token
if err := recover(); err != nil {
ch <- Result{Panic, id, nil, nil, fmt.Errorf("panic: %v", err)}
}
}()
type runOneCh struct {
ress []int64
errInfos map[int64]string
err error
}
errCh := make(chan runOneCh)
go func(ch chan runOneCh, id int64) {
ress, errInfos, err := m.RunOne(id)
errCh <- runOneCh{ress, errInfos, err}
}(errCh, id)
select {
case runOneRes := <-errCh:
if runOneRes.err != nil {
ch <- Result{Error, id, nil, nil, runOneRes.err}
} else {
ch <- Result{Success, id, runOneRes.ress, nil, nil}
}
case <-time.After(params.Deadline):
ch <- Result{Timeout, id, nil, nil, errors.New("timeout")}
}
}
// 初始化运行参数
func NewParams() (params *RunParam) {
params = new(RunParam)
flag.Int64Var(¶ms.Start, "start", 0, "")
flag.Int64Var(¶ms.End, "end", 0, "")
flag.IntVar(¶ms.Step, "step", 100, "")
var second int
flag.IntVar(&second, "second", 5, "")
flag.Parse()
params.Deadline = time.Second * time.Duration(second)
return
}
// 运行参数检测
func CheckParams(params *RunParam) error {
if params.End <= params.Start {
return fmt.Errorf("ress range err, %+v", *params)
}
if params.Deadline <= 0 {
return fmt.Errorf("ress deadline err, %+v", *params)
}
return nil
}
另外,用到了utils的的相关代码,下面贴一下
const (
Red = " 33[31m"
Yellow = " 33[33m"
Green = " 33[32m"
)
func PrintlnColorful(color string, vals ...interface{}) {
fmt.Printf(color)
fmt.Println(vals...)
fmt.Printf(" 33[0m")
}
func PrintfColorful(color string, format string, vals ...interface{}) {
fmt.Printf(color)
fmt.Printf(format, vals...)
fmt.Printf(" 33[0m")
}
- 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 数组属性和方法
- 在Centos上搭建Maven中央仓库的方法
- 详解Ubuntu16.04启动器图标异常解决方法
- Linux(ubuntu)下实现增加/删除文件权限
- Vim中文件编码处理与重新打开乱码文件详解
- Linux常用命令mkdir详解
- CentOS6.5环境下使用rsync增量同步备份文件的方法
- Linux 搭建Git服务器的方法
- Linux中无法远程连接数据库问题的解决方法
- VIM实现文件快速跳转插件详解
- 详解linux usb host驱动编写入门
- CentOS服务器平台搭建mysql主从复制与读写分离的方法
- Centos7中添加、删除Swap交换分区的方法
- Bash中文件描述符的详细介绍
- Linux 块设备驱动代码编写
- ubuntu中终端命令提示符太长的修改方法汇总