需求
一個接口調(diào)用時,接收到一個列表,十個元素,需要并發(fā)執(zhí)行十個任務(wù),每個任務(wù)都要返回執(zhí)行的結(jié)果和異常,然后對返回的結(jié)果裝填到一個切片列表里,統(tǒng)一返回結(jié)果。
需要協(xié)程處理的結(jié)構(gòu)體
type Order struct {
Name string `json:"name"`
Id int `json:"id"`
}
確定通道數(shù)量
一般按入?yún)⒌男枰幚淼脑財?shù)量為準(zhǔn)
taskNum:=10
初始化通道
orderCh := make(chan Order, taskNum) //接收返回的結(jié)果 errCh:=make(chanerror,taskNum)//接收返回的異常
發(fā)起執(zhí)行,我們使用sync.WaitGroup來監(jiān)聽執(zhí)行情況
wg := sync.WaitGroup{}
for i:=0; i < taskNum; i++ {
wg.Add(1)
go func() {
defer wg.Done()
if i == 3 {//模擬當(dāng)i=3的時候,返回一個異常
err := errors.New("there is an error")
errCh <- err
return
}
//組裝返回結(jié)果
res := Order{
Name: "num: " + strconv.Itoa(i),
Id: i,
}
orderCh <- res
}()
}
wg.Wait()?//等待所有任務(wù)執(zhí)行完畢
使用for-select接收執(zhí)行結(jié)果
orderList := make([]Order, taskNum) for i:=0; i1,超時問題
任務(wù)執(zhí)行過程中,需要控制每個任務(wù)的執(zhí)行時間,不能超過一定范圍,我們用定時器來解決這個問題
timeoutTime := time.Second * 3 //超時時間 taskTimer := time.NewTimer(timeoutTime) //初始化定時器 orderList := make([]Order, taskNum) for i:=0; i2, 協(xié)程panic問題
主程序是無法捕捉協(xié)程內(nèi)的panic,因此如果不手動處理,就會發(fā)生協(xié)程內(nèi)panic導(dǎo)致整個程序中止的情況,我們在defer里處理
for i:=0; i < taskNum; i++ { wg.Add(1) go func() { defer func () { wg.Done() //協(xié)程內(nèi)單獨(dú)捕捉異常 if r := recover(); r != nil { err := errors.New(fmt.Sprintf("System panic:%v", r)) errCh <- err //此處將panic信息轉(zhuǎn)為err返回,也可以按需求和異常等級進(jìn)行處理 return } }() ........ }() }3, 順序問題
返回的列表元素的順序,需要跟傳參的列表順序保持一致,這時我們需要定義個帶序號的結(jié)構(gòu)體
// 需要記錄原始順序的時候,定義個帶編號的結(jié)構(gòu)體 type OrderWithSeq struct { Seq int OrderItem Order } //重寫相關(guān)排序類型 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 } // 調(diào)整返回結(jié)果 orderCh := make(chan OrderWithSeq, taskNum) //接收帶序號的結(jié)構(gòu)體 //在執(zhí)行任務(wù)時,加入序號 for i:=0; i < taskNum; i++ { i:= i wg.Add(1) go func() { ···· //組裝返回結(jié)果 res := Order{ Name: "num: " + strconv.Itoa(i), Id: i, } orderCh <-OrderWithSeq { Seq: i, //帶上i這個序號 OrderItem: res, } }() //接收信息,也按帶序號的結(jié)構(gòu)體進(jìn)行組裝 orderSeqList := make([]OrderWithSeq, taskNum) for i:=0; i總結(jié)
標(biāo)準(zhǔn)模板如下:
type Order struct { Name string `json:"name"` Id int `json:"id"` } // 需要記錄原始順序的時候,定義個帶編號的結(jié)構(gòu)體 type OrderWithSeq struct { Seq int OrderItem Order } //重寫相關(guān)排序類型 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) //接收帶序號的結(jié)構(gòu)體 errCh := make(chan error, taskNum) //接收返回的異常 wg := sync.WaitGroup{} //在執(zhí)行任務(wù)時,加入序號 for i:=0; i < taskNum; i++ { i:= i wg.Add(1) go func() { defer func () { wg.Done() //協(xié)程內(nèi)單獨(dú)捕捉異常 if r := recover(); r != nil { err := errors.New(fmt.Sprintf("System panic:%v", r)) errCh <- err //此處將panic信息轉(zhuǎn)為err返回,也可以按需求和異常等級進(jìn)行處理 return } }() //組裝返回結(jié)果 res := Order{ Name: "num: " + strconv.Itoa(i), Id: i, } orderCh <-OrderWithSeq { Seq: i, //帶上i這個序號 OrderItem: res, } }() wg.Wait() //接收信息,也按帶序號的結(jié)構(gòu)體進(jìn)行組裝 orderSeqList := make([]OrderWithSeq, taskNum) timeoutTime := time.Second * 3 taskTimer := time.NewTimer(timeoutTime) for i:=0; i
-
接口
+關(guān)注
關(guān)注
33文章
9525瀏覽量
157091 -
定時器
+關(guān)注
關(guān)注
23文章
3368瀏覽量
123736
原文標(biāo)題:總結(jié)
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
接口調(diào)用并發(fā)執(zhí)行十個任務(wù)總結(jié)
評論