Search code examples
gochannelgoroutine

Wait result of multiple goroutines


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 function returned error I do not want to wait for another function, and just print the error. For example, I have this functions:

func methodInt(error bool) (int, error) {
    <-time.NewTimer(time.Millisecond * 100).C
    if error {
        return 0, errors.New("Some error")
    } else {
        return 1, nil
    }
}

func methodString(error bool) (string, error) {
    <-time.NewTimer(time.Millisecond * 120).C
    if error {
        return "", errors.New("Some error")
    } else {
        return "Some result", nil
    }
}

Here https://play.golang.org/p/-8StYapmlg is how I implemented it, but it has too much code I think. It can be simplified by using interface{} but I don't want to go this way. I want something simpler as, for example, can be implemented in C# with async/await. Probably there is some library that simplifies such operation.


Solution

  • 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, " ------------")
        }
    }