从 goroutines 中捕获返回值

新手上路,请多包涵

下面的代码给出了编译错误,说’unexpected go’:

 x := go doSomething(arg)

func doSomething(arg int) int{
    ...
    return my_int_value
}

我知道,如果我正常调用函数,即不使用 goroutine 或者我可以使用通道等,我可以获取返回值。

我的问题是为什么不能从 goroutine 中获取这样的返回值。

原文由 Nerve 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

严格的回答是你 可以 做到。这可能不是一个好主意。这是可以做到这一点的代码:

 var x int
go func() {
    x = doSomething()
}()

这将产生一个新的 goroutine,它将计算 doSomething() 然后将结果分配给 x 。问题是:你打算如何使用原始 goroutine 中的 x ?您可能想确保生成的 goroutine 已完成,这样您就不会出现竞争条件。但如果你想这样做,你需要一种与 goroutine 通信的方法,如果你有办法做到这一点,为什么不直接用它来发送值呢?

原文由 joshlf 发布,翻译遵循 CC BY-SA 3.0 许可协议

为什么无法从 goroutine 获取返回值并将其分配给变量?

运行 goroutine(异步)和从函数中获取返回值本质上是相互矛盾的行为。当你说 go 你的意思是“异步执行”或者更简单:“继续!不要等待函数执行完成”。但是,当您将函数返回值分配给变量时,您希望该值包含在变量中。所以当你这样做时 x := go doSomething(arg) 你是在说:“继续,不要等待函数!等等!我需要一个可以访问的返回值 x var就在下面的下一行!”

频道

从 goroutine 获取值的最自然的方式是通道。通道是连接并发 goroutine 的管道。您可以将值从一个 goroutine 发送到通道,然后将这些值接收到另一个 goroutine 或同步函数中。您可以使用 select 从不破坏并发的 goroutine 轻松获取值:

 func main() {

    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        time.Sleep(time.Second * 1)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(time.Second * 2)
        c2 <- "two"
    }()

    for i := 0; i < 2; i++ {
        // Await both of these values
        // simultaneously, printing each one as it arrives.
        select {
        case msg1 := <-c1:
            fmt.Println("received", msg1)
        case msg2 := <-c2:
            fmt.Println("received", msg2)
        }
    }
}

该示例取自 Go By Example

CSP 和消息传递

Go 在很大程度上基于 CSP 理论。上面的天真描述可以用 CSP 来精确概述(尽管我认为这超出了问题的范围)。我强烈建议至少熟悉 CSP 理论,因为它是 RAD。这些简短的引述给出了一个思考方向:

顾名思义,CSP 允许根据 独立运行 的组件进程来描述系统,并且仅通过 消息传递通信 相互交互。

在计算机科学中,消息传递将消息发送到进程并依赖于进程和支持基础设施来选择和调用实际代码来运行。消息传递不同于传统编程,在传统编程中,进程、子例程或函数是直接按名称调用的。

原文由 I159 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题