2 回答

TA貢獻1790條經驗 獲得超9個贊
首先,注冊一個延遲函數來恢復應該是函數中的第一行,因為因為你是最后做的,它甚至不會被到達,因為defer已經發生恐慌之前的行/代碼所以延遲函數沒有被注冊哪個將恢復恐慌狀態。
因此,將您的do()功能更改為:
func do() {
defer func() {
if err := recover(); err != nil {
fmt.Println("Restored:", err)
}
}()
str := "abc"
fmt.Print(str[3])
}
第二:僅此一項不會使您的代碼工作,因為您調用wg.Defer()了一個延遲函數,該函數只會在main()完成后運行- 這絕不是因為您調用wg.Wait()了main(). 所以wg.Wait()等待wg.Done()調用,但wg.Done()直到wg.Wait()返回才會運行調用。這是一個僵局。
您應該wg.Done()從do()函數調用,在延遲函數中,如下所示:
var wg sync.WaitGroup
func do() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
wg.Done()
}()
str := "abc"
fmt.Print(str[3])
}
func main() {
for i := 0; i < 1; i++ {
wg.Add(1)
go do()
}
wg.Wait()
fmt.Println("This line should be printed after all those invocations fail.")
}
輸出(在Go Playground上試試):
Restored: runtime error: index out of range
This line should be printed after all those invocations fail.
這當然需要將wg變量移動到全局范圍。另一種選擇是將其do()作為參數傳遞給。如果您決定采用這種方式,請注意您必須將指針傳遞給WaitGroup,否則只會傳遞一個副本(WaitGroup是一種struct類型)并且調用WaitGroup.Done()副本不會對原始文件產生影響。
隨著傳遞WaitGroup到do():
func do(wg *sync.WaitGroup) {
defer func() {
if err := recover(); err != nil {
fmt.Println("Restored:", err)
}
wg.Done()
}()
str := "abc"
fmt.Print(str[3])
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1; i++ {
wg.Add(1)
go do(&wg)
}
wg.Wait()
fmt.Println("This line should be printed after all those invocations fail.")
}
輸出是一樣的。在Go Playground上試試這個變體。

TA貢獻1846條經驗 獲得超7個贊
出色地解釋了如何正確使用WaitGroup及其功能Wait和Done
我喜歡WaitGroup簡單。但是,我不喜歡我們需要傳遞對 goroutine 的引用,因為這意味著并發邏輯將與您的業務邏輯混合。
所以我想出了這個通用函數來為我解決這個問題:
// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
var waitGroup sync.WaitGroup
waitGroup.Add(len(functions))
defer waitGroup.Wait()
for _, function := range functions {
go func(copy func()) {
defer waitGroup.Done()
copy()
}(function)
}
}
所以你的例子可以這樣解決:
func do() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
str := "abc"
fmt.Print(str[3])
}
func main() {
Parallelize(do, do, do)
fmt.Println("This line should be printed after all those invocations fail.")
}
如果你想使用它,你可以在這里找到它https://github.com/shomali11/util
- 2 回答
- 0 關注
- 186 瀏覽
添加回答
舉報