等待多个协程的结果

Wait result of multiple goroutines

我正在寻找一种方法来异步执行两个 return 不同结果和错误的函数,等待它们完成并打印两个结果。另外,如果其中一个函数 returned 出错,我不想等待另一个函数,而只是打印错误。 例如,我有这个功能:

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
    }
}

这里 https://play.golang.org/p/-8StYapmlg 是我实现它的方式,但我认为它的代码太多了。它可以通过使用 interface{} 来简化,但我不想这样做。我想要更简单的东西,例如,可以使用 async/await 在 C# 中实现。可能有一些库可以简化这样的操作。

更新:感谢您的回复!我得到帮助的速度真是太棒了!我喜欢 WaitGroup 的用法。它显然使代码对更改更加健壮,因此我可以轻松地添加另一个异步方法,而无需最终更改方法的确切数量。但是,与 C# 中的相同代码相比,仍然有很多代码。我知道在 go 中我不需要显式地将方法标记为异步,使它们实际上成为 return 任务,但是方法调用看起来简单得多,例如,考虑这个 link actually catching exception is also needed 顺便说一句,我发现在我的任务中我实际上不需要知道 returning 我想要 运行 异步的函数类型,因为它无论如何都会被编组到 json,现在我只是在go-kit的端点层调用多个服务。

我已经创建了一个更小的、独立的示例,说明如何异步地拥有两个 go 例程 运行 并等待它们完成或在发生错误时退出程序(请参阅下面的解释) :

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
        }
    }
}

我所做的是创建一个用于同步两个 go 例程的通道。写入和读取它块。该通道用于传递错误值,如果函数成功则为 nil。

最后,我从通道中为每个异步 go 例程读取了一个值。这会阻塞,直到收到一个值。如果发生错误,我退出循环,从而退出程序。

函数随机成功或失败。

我希望这能让你继续了解如何协调 go 例程,如果没有,请在评论中告诉我。

注意 如果你在 Go Playground 中 运行 这个,rand.Seed 什么都不做,playground 总是有相同的 "random" 数字,因此行为不会改变。

我觉得这里sync.WaitGroup可以用。它可以等待不同的动态数量的 goroutines。

您应该为错误和结果创建两个通道,如果没有错误则首先读取错误然后读取结果,此示例应该适用于您的用例:

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