日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程)

發(fā)布時間:2023/11/28 生活经验 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在多協(xié)程并發(fā)環(huán)境下,我們常常會碰到以下兩個問題。假設(shè)我們現(xiàn)在有 2 個協(xié)程,我們叫它們協(xié)程 A 和 B 。

  • 【問題1】如果協(xié)程 A 發(fā)生了 panic ,協(xié)程 B 是否會因為協(xié)程 A 的 panic 而掛掉?
  • 【問題2】如果協(xié)程 A 發(fā)生了 panic ,協(xié)程 B 是否能用 recover 捕獲到協(xié)程 A 的 panic

答案分別是:會、不能。

1.【問題1】

  • 【問題1】如果協(xié)程 A 發(fā)生了 panic ,協(xié)程 B 是否會因為協(xié)程 A 的 panic 而掛掉?
package mainimport ("fmt""time"
)func main() {// 協(xié)程 Ago func() {for {fmt.Println("協(xié)程 A")}}()// 協(xié)程 Bgo func() {time.Sleep(1 * time.Microsecond) // 確保 協(xié)程 A 先運行起來panic("協(xié)程 B panic")}()time.Sleep(10 * time.Second) // 充分等待協(xié)程 B 觸發(fā) panic 完成和協(xié)程 A 執(zhí)行完畢fmt.Println("main end")
}

輸出結(jié)果:

協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
協(xié)程 A
panic: 協(xié)程 B panicgoroutine 6 [running]:
main.main.func2()/home/wohu/GoCode/src/hello.go:19 +0x46
created by main.main/home/wohu/GoCode/src/hello.go:17 +0x51
exit status 2

可以看到,在協(xié)程 B 觸發(fā) panic 之后,協(xié)程 A 并沒有繼續(xù)打印,并且主協(xié)程的 main end 也沒有打印出來,充分說明了在 B 協(xié)程觸發(fā) panic 之后,在 A 協(xié)程也會因此掛掉,且主協(xié)程也會掛掉。

2.【問題2】

  • 【問題2】如果協(xié)程 A 發(fā)生了 panic ,協(xié)程 B 是否能用 recover 捕獲到協(xié)程 A 的 panic

精簡上面的代碼如下:

package mainimport ("fmt""time"
)func main() {defer func() {if err := recover(); err != nil {fmt.Printf("panic err is %s", err)}}()// 協(xié)程 Bgo func() {panic("協(xié)程 B panic")}()time.Sleep(1 * time.Second) // 充分等待協(xié)程 B 觸發(fā) panic 完成fmt.Println("main end")
}

我們開啟 1 個協(xié)程 B,并在主協(xié)程中增加 recover 機制,嘗試在主協(xié)程中捕獲協(xié)程 B 觸發(fā)的 panic , 但是結(jié)果未能如愿。 打印結(jié)果如下:

panic: 協(xié)程 B panicgoroutine 5 [running]:
main.main.func2()/home/wohu/GoCode/src/hello.go:18 +0x39
created by main.main/home/wohu/GoCode/src/hello.go:17 +0x59
exit status 2

從結(jié)果可以看到, recover 并沒有生效,所以我們可以下結(jié)論:

哪個協(xié)程發(fā)生 panic,就需要在哪個協(xié)程自身中 recover 。

改成如下代碼,可以正常 recover。

package mainimport ("fmt""time"
)func main() {go func() {defer func() {if err := recover(); err != nil {fmt.Printf("panic err is %s\n", err)}}()panic("panic")}()time.Sleep(1 * time.Second) // 充分等待協(xié)程觸發(fā) panic 完成fmt.Println("main end")
}

輸出結(jié)果:

panic err is panic
main end

所以結(jié)論如下:

協(xié)程A發(fā)生 panic ,協(xié)程B無法 recover 到協(xié)程A的 panic ,只有協(xié)程自己內(nèi)部的 recover 才能捕獲自己拋出的 panic

3. 業(yè)務(wù)開發(fā)實踐

package mainimport ("fmt""sync""time"
)// 該函數(shù)的參數(shù)為多個業(yè)務(wù)邏輯函數(shù),且函數(shù)個數(shù)為變長參數(shù)
func allTasks(tasks ...func()) {var wg sync.WaitGroupfor _, t := range tasks {wg.Add(1) // 每啟動一個協(xié)程等待組加 1go func(f func()) { // 匿名函數(shù)的參數(shù)為業(yè)務(wù)邏輯函數(shù)defer func() {// 在每個協(xié)程內(nèi)部接收該協(xié)程自身拋出來的 panicif err := recover(); err != nil {fmt.Println("defer", err)}wg.Done() // 每個協(xié)程結(jié)束時給 等待組減 1}()f() // 業(yè)務(wù)函數(shù)調(diào)用執(zhí)行}(t) // 將當(dāng)前的業(yè)務(wù)函數(shù)名傳遞給協(xié)程}wg.Wait()}// 業(yè)務(wù)邏輯 A
func A() {fmt.Println("A func begin")panic("error A")
}// 業(yè)務(wù)邏輯 B
func B() {fmt.Println("B func begin")
}func main() {allTasks(A, B) // 將業(yè)務(wù)邏輯函數(shù)名 A B 傳遞給封裝好的處理函數(shù)time.Sleep(1 * time.Second)fmt.Println("main end")
}

輸出結(jié)果

B func begin
A func begin
defer error A
main end

這樣我們就實現(xiàn)了一個通用的并發(fā)處理邏輯,每次調(diào)用我們只需要把業(yè)務(wù)邏輯的函數(shù)傳入即可,不用每次自己單獨編寫一套并發(fā)控制邏輯;同時調(diào)用邏輯 B 就不會因為調(diào)用邏輯 A 的 panic 而掛掉了,容錯率更高。在業(yè)務(wù)開發(fā)中我們可以參考這種實現(xiàn)方式。

package mainimport (
"fmt"
"sync"
)
var wg sync.Waitgroupfunc div(num int) {
defer func() {
err := recover()
if err != nil {
fmt.Println(err) }
wg.Done()
}()
fmt.Printf("10/%d=%d\n", num, 10/num)
}
func main() {
for i:=0; i<10;i++ {
wg.Add(i)
go div(i)
}
wg.Wait()
}

總結(jié)

以上是生活随笔為你收集整理的Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。