0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

接口调用并发执行十个任务总结

马哥Linux运维 来源:网络整理 2023-11-15 10:37 次阅读

需求

一个接口调用时,接收到一个列表,十个元素,需要并发执行十个任务,每个任务都要返回执行的结果和异常,然后对返回的结果装填到一个切片列表里,统一返回结果。

需要协程处理的结构体

type Order struct {  
  Name string `json:"name"`  
  Id int `json:"id"`  
}

确定通道数量

一般按入参的需要处理的元素数量为准

taskNum:=10

初始化通道

orderCh := make(chan Order, taskNum) //接收返回的结果
errCh:=make(chanerror,taskNum)//接收返回的异常

发起执行,我们使用sync.WaitGroup来监听执行情况

wg := sync.WaitGroup{}
for i:=0; i < taskNum; i++ {
   wg.Add(1)
   go func() {
     defer wg.Done()
     if i == 3 {//模拟当i=3的时候,返回一个异常
         err := errors.New("there is an error")
         errCh <- err 
         return
     }
     //组装返回结果
     res := Order{  
         Name: "num: " + strconv.Itoa(i),  
         Id: i,  
         }
     orderCh <- res    
  }()
}
wg.Wait() //等待所有任务执行完毕

使用for-select接收执行结果

orderList := make([]Order, taskNum)
for i:=0; i

1,超时问题

任务执行过程中,需要控制每个任务的执行时间,不能超过一定范围,我们用定时器来解决这个问题

timeoutTime := time.Second * 3  //超时时间
taskTimer := time.NewTimer(timeoutTime) //初始化定时器
orderList := make([]Order, taskNum)
for i:=0; i

2, 协程panic问题

主程序是无法捕捉协程内的panic,因此如果不手动处理,就会发生协程内panic导致整个程序中止的情况,我们在defer里处理

for i:=0; i < taskNum; i++ {
   wg.Add(1)
   go func() {
     defer func () {
      wg.Done()
      //协程内单独捕捉异常  
      if r := recover(); r != nil {  
        err := errors.New(fmt.Sprintf("System panic:%v", r))  
        errCh <- err //此处将panic信息转为err返回,也可以按需求和异常等级进行处理
        return
      }
     }()
   ........
  }()
}

3, 顺序问题

返回的列表元素的顺序,需要跟传参的列表顺序保持一致,这时我们需要定义个带序号的结构体

// 需要记录原始顺序的时候,定义个带编号的结构体  
type OrderWithSeq struct {  
    Seq int  
    OrderItem Order  
}  
//重写相关排序类型
type BySeq []OrderWithSeq  
  
func (a BySeq) Len() int {  
    return len(a)  
}  
func (a BySeq) Swap(i, j int) {  
    a[i], a[j] = a[j], a[i]  
}  
func (a BySeq) Less(i, j int) bool {  
    return a[i].Seq < a[j].Seq  
}
// 调整返回结果
orderCh := make(chan OrderWithSeq, taskNum) //接收带序号的结构体
//在执行任务时,加入序号
for i:=0; i < taskNum; i++ {
   i:= i
   wg.Add(1)
   go func() {
     ····
     //组装返回结果
     res := Order{  
         Name: "num: " + strconv.Itoa(i),  
         Id: i,  
         }
     orderCh <-OrderWithSeq {
         Seq: i, //带上i这个序号
         OrderItem: res,
     }
  }()
 //接收信息,也按带序号的结构体进行组装
 orderSeqList := make([]OrderWithSeq, taskNum)
 for i:=0; i

总结

标准模板如下:

type Order struct {  
  Name string `json:"name"`  
  Id int `json:"id"`  
}


// 需要记录原始顺序的时候,定义个带编号的结构体  
type OrderWithSeq struct {  
    Seq int  
    OrderItem Order  
}  
//重写相关排序类型
type BySeq []OrderWithSeq  
  
func (a BySeq) Len() int {  
    return len(a)  
}  
func (a BySeq) Swap(i, j int) {  
    a[i], a[j] = a[j], a[i]  
}  
func (a BySeq) Less(i, j int) bool {  
    return a[i].Seq < a[j].Seq  
}


taskNum := 10 
orderCh := make(chan OrderWithSeq, taskNum) //接收带序号的结构体
errCh := make(chan error, taskNum) //接收返回的异常
wg := sync.WaitGroup{}
//在执行任务时,加入序号
for i:=0; i < taskNum; i++ {
   i:= i
   wg.Add(1)
   go func() {
     defer func () {
      wg.Done()
      //协程内单独捕捉异常  
      if r := recover(); r != nil {  
        err := errors.New(fmt.Sprintf("System panic:%v", r))  
        errCh <- err //此处将panic信息转为err返回,也可以按需求和异常等级进行处理
        return
      }
     }()
     //组装返回结果
     res := Order{  
         Name: "num: " + strconv.Itoa(i),  
         Id: i,  
         }
     orderCh <-OrderWithSeq {
         Seq: i, //带上i这个序号
         OrderItem: res,
     }
  }()
 wg.Wait()
  //接收信息,也按带序号的结构体进行组装
 orderSeqList := make([]OrderWithSeq, taskNum)
 timeoutTime := time.Second * 3 
 taskTimer := time.NewTimer(timeoutTime)
 for i:=0; i
                        
                
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7640

    浏览量

    148509
  • 定时器
    +关注

    关注

    23

    文章

    3148

    浏览量

    112041

原文标题:总结

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    NI-DAQmx中的十个函数

    学会NI-DAQmx中的十个函数解决80%的数据采集应用问题
    发表于 04-07 17:29

    有刷电机转子十个曹 线怎么绕 线头怎么接法

    十个曹 线怎么绕 线头怎么接法
    发表于 01-01 18:50

    请问一协调器连接十个终端,如何能获取十个终端的短地址?

    本帖最后由 一只耳朵怪 于 2018-5-24 14:22 编辑 一协调器连接十个终端,如何能获取十个终端的短地址,求思路
    发表于 05-22 08:57

    十个练习让你学会Verilog语言

    10 Verilog 练习,进阶级教程 完整的pdf格式文档电子发烧友下载地址(共26页): 十个练习让你学会Verilog语言.pdf
    发表于 07-03 02:04

    arduino学习必须掌握的十个函数

    必须掌握的函数,一共只有十个,所以一定要记住,没有什么难的1.数字输入输出I/O·① pinMode(pin, mode) 说明:数字IO 口输入输出模式定义函数,pin 表示为0~13, mode
    发表于 07-19 09:47

    串口发送数据超过十个数据就出现数据丢失

    自己编写的程序,给串口1发送数据,然后串口1再发回主机,但是出现问题,只能发十个数据,超过十个就出现数据丢失,代码哪里出错了呢?
    发表于 01-29 07:35

    Altium-Designer-很好用的几十个技巧

    Altium-Designer-很好用的几十个技巧
    发表于 03-08 09:26

    mini板下载ucosii调用任务只有一程序在执行是为什么?

    在mini板上用ucos操作系统调用了三任务分别是跑马灯、DHT11测温湿度、BMP180测气压,发现程序只全程执行了一次就停住了,有人遇到过这种情况吗??程序代码如下:(串口打印出
    发表于 05-15 00:52

    请问为什么这十个PCB设计错误要避免?

    为什么这十个PCB设计错误要避免
    发表于 03-17 06:22

    扩展示波器用途的十个技巧速看

    本文将介绍扩展示波器用途的十个技巧,它们可以帮助你节省时间,并使你成为公司的DSO专家。
    发表于 04-29 06:15

    ECG十个电极和12导联

    ECG十个电极和12导联1.对ECG获取心电图信息不是很了解,ECG只有十个电极为什么称作12导联?电极和导联之间有什么关联?2.什么叫做右脚驱动?为什么不能用左脚?3.除了PPG、ECG、还有BCG技术,如果做心率的检测用哪种技术更好?
    发表于 12-08 16:31

    微机原理与接口技术知识总结

    系统总线:数据总线(双向)、地址总线(单向)、控制总线冯·诺依曼关于程序存储的原则:指令和数据预先存放在内存中bit为二进制位,8bit=1字节,1字=2字节BCD码:用4位二进制数来表示1位进制数中0~9这十个数8086CPU:数据总线16位,地址总线20位,最
    发表于 12-10 06:07

    任务编程多任务处理是指什么

    。多任务操作系统使用某种调度策略支持多个任务并发执行。每个任务被创建时分配时间片(几到上百毫秒
    发表于 12-22 08:30

    HarmonyOS如何使用异步并发能力进行开发

    UI的同时,后台也能执行耗时操作,从而避免应用出现卡顿。 并发能力在多种场景中都有应用,其中包括单次I/O任务、CPU密集型任务、I/O密集型任务
    发表于 09-22 17:35

    Dispatch Queue任务执行与Dispatch Source

    导读本文为读《Concurrency Programming Guide》笔记第三篇,在对OS X和iOS应用开发中实现任务异步执行的技术、注意事项、Operation与Dispatch
    发表于 10-11 11:54 0次下载