Wait result of multiple goroutines

前端 未结 3 1727
走了就别回头了
走了就别回头了 2021-01-11 21:01

I am searching a way to execute asynchronously two functions in go which returns different results and errors, wait for them to finish and print both results. Also if one of

相关标签:
3条回答
  • 2021-01-11 21:34

    I have created a smaller, self-contained example of how you can have two go routines run asynchronously and wait for both to finish or quit the program if an error occurs (see below for an explanation):

    package main
    
    import (
        "errors"
        "fmt"
        "math/rand"
        "time"
    )
    
    func main() {
        rand.Seed(time.Now().UnixNano())
    
        // buffer the channel so the async go routines can exit right after sending
        // their error
        status := make(chan error, 2)
    
        go func(c chan<- error) {
            if rand.Intn(2) == 0 {
                c <- errors.New("func 1 error")
            } else {
                fmt.Println("func 1 done")
                c <- nil
            }
        }(status)
    
        go func(c chan<- error) {
            if rand.Intn(2) == 0 {
                c <- errors.New("func 2 error")
            } else {
                fmt.Println("func 2 done")
                c <- nil
            }
        }(status)
    
        for i := 0; i < 2; i++ {
            if err := <-status; err != nil {
                fmt.Println("error encountered:", err)
                break
            }
        }
    }
    

    What I do is create a channel that is used for synchronization of the two go routines. Writing to and reading from it blocks. The channel is used to pass the error value around, or nil if the function succeeds.

    At the end I read one value per async go routine from the channel. This blocks until a value is received. If an error occurs, I exit the loop, thus quitting the program.

    The functions either succeed or fail randomly.

    I hope this gets you going on how to coordinate go routines, if not, let me know in the comments.

    Note that if you run this in the Go Playground, the rand.Seed will do nothing, the playground always has the same "random" numbers, so the behavior will not change.

    0 讨论(0)
  • 2021-01-11 21:43

    You should create two channels for errors and results, then first read errors if no erorrs then read the results, this sample should works for your use case:

    package main
    
    import (
        "errors"
        "sync"
    )
    
    func test(i int) (int, error) {
        if i > 2 {
            return 0, errors.New("test error")
        }
        return i + 5, nil
    }
    
    func test2(i int) (int, error) {
        if i > 3 {
            return 0, errors.New("test2 error")
        }
        return i + 7, nil
    }
    
    func main() {
        results := make(chan int, 2)
        errors := make(chan error, 2)
        var wg sync.WaitGroup
        wg.Add(1)
        go func() {
            defer wg.Done()
            result, err := test(3)
            if err != nil {
                errors <- err
                return
            }
            results <- result
        }()
        wg.Add(1)
        go func() {
            defer wg.Done()
            result, err := test2(3)
            if err != nil {
                errors <- err
                return
            }
            results <- result
        }()
    
        // here we wait in other goroutine to all jobs done and close the channels
        go func() {
            wg.Wait()
            close(results)
            close(errors)
        }()
        for err := range errors {
            // here error happend u could exit your caller function
            println(err.Error())
            return
    
        }
        for res := range results {
            println("--------- ", res, " ------------")
        }
    }
    
    0 讨论(0)
  • 2021-01-11 21:49

    I think here sync.WaitGroup can be used. It can waits for different and dynamic number of goroutines.

    0 讨论(0)
提交回复
热议问题