首頁 >後端開發 >Golang >如何在錯誤時停止從通道讀取?

如何在錯誤時停止從通道讀取?

WBOY
WBOY轉載
2024-02-09 14:00:11716瀏覽

如何在錯誤時停止從通道讀取?

php小編子墨為您介紹如何在錯誤時停止從通道讀取。在進行通道讀取操作時,有時會遇到錯誤情況,例如通道已關閉或讀取逾時。為了確保程式的穩定性和可靠性,我們需要在這些錯誤發生時及時停止讀取操作。可以透過設定錯誤處理程序或使用異常處理機制來實現,在捕獲到錯誤後,立即終止讀取操作,並進行相應的錯誤處理。這樣可以有效避免程式因錯誤而導致的異常情況,提高程式碼的健全性和可維護性。

問題內容

一旦遇到錯誤,我想停止從通道讀取。我認為我需要使用 errroup.WithContext() 但我無法完全理解如何整合它。

這是輸出:

Thread 2: STARTED
Thread 1: STARTED
Thread 0: STARTED
Thread 2: GOT=0
Thread 1: GOT=1
Thread 0: GOT=2
Thread 0: FAILED
Thread 1: GOT=3
Thread 2: GOT=4
Thread 2: GOT=5
Thread 1: GOT=6
Thread 1: GOT=7
Thread 2: GOT=8
panic: Thread 0: FAILED
package main

import (
    "fmt"
    "time"

    "golang.org/x/sync/errgroup"
)

func main() {
    const threads = 3

    ch := make(chan int, threads)

    eg := errgroup.Group{}

    for i := 0; i < threads; i++ {
        i := i
        eg.Go(func() error {
            fmt.Printf("Thread %d: STARTED\n", i)
            for n := range ch {
                fmt.Printf("Thread %d: GOT=%d\n", i, n)
                time.Sleep(time.Duration(1) * time.Second)
                // Simulate failed thread
                if n == 2 {
                    fmt.Printf("Thread %d: FAILED\n", i)
                    return fmt.Errorf("Thread %d: FAILED", i)
                }
            }
            return nil
        })
    }

    for i := 0; i < 9; i++ {
        ch <- i
    }

    close(ch)

    if err := eg.Wait(); err != nil {
        panic(err)
    }
}

............................................... .... ......................................

解決方法

errroup.WithContext()# 可能是最好的方法(如你所猜測的)。 這個答案值得一讀;它提供了全面的解釋(我不會嘗試複製!)。

但是,由於這可能很難理解,這裡是使用您的程式碼的一種解決方案(playground ):

package main

import (
    "context"
    "fmt"
    "time"

    "golang.org/x/sync/errgroup"
)

func main() {
    const threads = 3

    ch := make(chan int, threads)

    eg, ctx := errgroup.WithContext(context.Background())
    for i := 0; i < threads; i++ {
        i := i
        eg.Go(func() error {
            fmt.Printf("Thread %d: STARTED\n", i)
            for n := range ch {
                fmt.Printf("Thread %d: GOT=%d\n", i, n)
                time.Sleep(time.Duration(1) * time.Second)
                // Simulate failed thread
                if n == 2 {
                    fmt.Printf("Thread %d: FAILED\n", i)
                    return fmt.Errorf("Thread %d: FAILED", i)
                }
                // For the purpose of this example we will just check the context after
                // doing the work.
                if ctx.Err() != nil {
                    fmt.Printf("Thread %d: Quiting due to context\n", i)
                    return fmt.Errorf("Thread %d: Context cancelled: ", i)
                }
            }
            return nil
        })
    }

    // We want to stop sending new work if there is a failure (otherwise `ch <- i` will block permanently);
sendLoop:
    for i := 0; i < 9; i++ {
        select {
        case ch <- i:
        case <-ctx.Done():
            fmt.Printf("stopped\n")
            break sendLoop // Just exit the loop if something goes wrong (you may want to do something else here)
        }
    }
    close(ch) // Note: Important that this happens even if there is an error (otherwise `for n := range ch` may block, leaking goroutines)
    fmt.Printf("all sent\n")
    if err := eg.Wait(); err != nil {
        panic(err)
    }
}

以上是如何在錯誤時停止從通道讀取?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除