【问题标题】:Is it possible to receive a result from one of a number of goroutines in Go?是否可以从 Go 中的多个 goroutine 之一接收结果?
【发布时间】:2010-12-16 19:56:51
【问题描述】:

我最近才了解了 Google 的编程语言 Go。我对它提供的并发支持很感兴趣,并着手了解更多有关它的信息。但是,我去看看 Go 是如何实现特定的并发特性的,到目前为止,我还没有看到任何证据表明这个特性存在。

这是一种假设情况:假设我们正在编写一个函数来确定特定输入的 Foo 值。对于任何给定的输入,Foo 值可以在域 A 或域 B 中找到(不在两者中)。这些领域的搜索技术大相径庭,但它们的共同特点是成功的搜索往往会很快返回,而不成功的搜索必须遍历整个数据集才能详尽无遗,因此需要很长时间。

现在,在其他使用并发的语言(例如Cilk)中,可以对函数 Foosearch 进行编程,以便它产生一个 Asearch 函数和一个 Bsearch 函数。这些函数将同时运行,并且每当 其中一个 提出答案时,该答案将报告给调用函数 Foosearch,该函数将终止它产生的任何未返回的函数。 p>

但是,使用 Go 的 goroutine,您似乎只能将两个例程与一个通道连接 - 因此您无法设置 Asearch 或 Bsearch 可以发送到的通道,具体取决于哪个先找到答案,并且Foosearch 从中读取。看起来你不能在没有阻塞的情况下从一个频道读取 - 所以你不能让 Foosearch 启动 Asearch 和 Bsearch 并从两者设置频道,然后在循环中运行以查看其中一个或另一个是否产生了一个答案。

我对 Go 并发限制的理解正确吗?有没有其他方法可以达到给定的结果?

【问题讨论】:

    标签: concurrency go goroutine


    【解决方案1】:

    不,我不相信你对围棋限制的理解是正确的。

    一方面,我在 Go 中看到的任何东西都没有限制通道在两个例程之间进行通信。您可以将相同的通道传递给 Asearch 和 Bsearch,然后任何一个完成都可以在该通道上发送结果。

    如果您想使用两个通道,并等待其中一个获得结果,您可以使用select 语句。来自Go tutorial,一个选择用于发送请求的通道的示例,一个用于指示服务器退出的示例:

    21    func server(op binOp, service chan *request, quit chan bool) {
    22        for {
    23            select {
    24            case req := <-service:
    25                go run(op, req);  // don't wait for it
    26            case <-quit:
    27                return;
    28            }
    29        }
    30    }
    

    此外,虽然从频道接收通常会阻塞,但您也可以从频道执行non-blocking receive

    如果接收表达式用于 赋值或初始化 表格

    x, ok = <-ch
    x, ok := <-ch
    var x, ok = <-ch
    

    接收操作变为 非阻塞。如果操作可以 继续,布尔变量 ok 将 设置为 true 并将值存储在 X;否则 ok 设置为 false 和 x 为其类型设置为零值 (§The zero value)。

    因此,有几种方法可以在不阻塞的情况下等待多个 goroutine 的结果。我想我会使用select 多路复用多个通道,因为这样您就可以轻松判断哪个例程返回了结果,而无需将该信息打包到您发送的值中或执行其他某种形式的 out-of-频段通信。

    【讨论】:

      【解决方案2】:

      您可以使用select 关键字从多个渠道接收。

      该值将取自结果比其他通道更早的通道。

      var c1, c2 chan int;
      var result int;
      
      select {
      case result = <-c1:
          print("received ", result, " from c1\n");
      case result = <-c2:
          print("received ", result, " from c2\n");
      }
      

      Reference

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-03
        • 1970-01-01
        • 2019-02-08
        • 2021-07-07
        • 2018-04-05
        • 2022-01-04
        • 2018-01-12
        • 1970-01-01
        相关资源
        最近更新 更多