Go 語(yǔ)言函數(shù):并發(fā)任務(wù)執(zhí)行中的錯(cuò)誤處理技術(shù)
在 Golang 中使用并發(fā)函數(shù)執(zhí)行任務(wù)時(shí),處理錯(cuò)誤至關(guān)重要。本文介紹了多種錯(cuò)誤處理技術(shù),并提供了有關(guān)如何將它們應(yīng)用于實(shí)際場(chǎng)景的實(shí)戰(zhàn)案例。
錯(cuò)誤處理技術(shù)
1. 返回值
最簡(jiǎn)單的方法是使用返回值來(lái)傳遞錯(cuò)誤。函數(shù)可以返回錯(cuò)誤值,調(diào)用者可以檢查該值并采取適當(dāng)?shù)拇胧?/p>
func getSum(a, b int) (int, error) {
if a < 0 || b < 0 {
return 0, errors.New("inputs must be non-negative")
}
return a + b, nil
}
2. 拋出異常
Go 語(yǔ)言提供了一個(gè)內(nèi)置的異常機(jī)制??梢允褂?panic 函數(shù)拋出異常,由調(diào)用者使用 recover 函數(shù)捕獲。
立即學(xué)習(xí)“go語(yǔ)言免費(fèi)學(xué)習(xí)筆記(深入)”;
func getArea(width, height int) (int, error) {
if width < 0 || height < 0 {
panic("invalid width or height")
}
return width * height, nil
}
3. channel
通道提供了另一種用于并發(fā)任務(wù)錯(cuò)誤處理的機(jī)制。可以創(chuàng)建一個(gè)接收錯(cuò)誤的 channel,然后將該 channel 傳遞給任務(wù) goroutine。如果任務(wù)出錯(cuò),goroutine 將向 channel 發(fā)送錯(cuò)誤。
func getAverage(numbers []int) (float64, error) {
errCh := make(chan error)
go func() {
sum := 0
for _, n := range numbers {
sum += n
}
avg := float64(sum) / float64(len(numbers))
if len(numbers) == 0 {
errCh <- errors.New("empty slice")
} else {
errCh <- nil
}
}()
select {
case err := <-errCh:
return 0, err
case <-time.After(1 * time.Second):
return 0, errors.New("timeout")
}
}
實(shí)戰(zhàn)案例
文件讀取并處理
以下函數(shù)使用并發(fā) goroutine 讀取并處理文件中的行。錯(cuò)誤通過(guò) channel 傳遞。
func processLines(filePath string) ([][]string, error) {
errCh := make(chan error)
file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()
lines := [][]string{}
nLines := 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
nLines++
go func(line string) {
parts := strings.Split(line, ",")
errCh <- processLine(parts)
}(line)
}
for i := 0; i < nLines; i++ {
err := <-errCh
if err != nil {
return nil, err
}
}
return lines, nil
}
HTTP 請(qǐng)求并發(fā)
以下函數(shù)使用并發(fā) goroutine 發(fā)出 HTTP 請(qǐng)求。錯(cuò)誤通過(guò)返回的 channel 傳遞。
func sendRequests(urls []string) ([][]byte, error) {
respCh := make(chan []byte, len(urls))
errCh := make(chan error, len(urls))
for _, url := range urls {
go func(url string) {
resp, err := http.Get(url)
if err != nil {
errCh <- err
} else {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
errCh <- err
} else {
respCh <- body
}
}
}(url)
}
responses := [][]byte{}
for i := 0; i < len(urls); i++ {
select {
case resp := <-respCh:
responses = append(responses, resp)
case err := <-errCh:
return nil, err
}
}
return responses, nil
}