是否有可能从Go中的一些goroutine中获得结果?

时间:2009-11-15 17:46:14

标签: concurrency go goroutine

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

这是一个假设的情况:假设我们正在编程一个函数来确定特定输入的Foo值。对于任何给定的输入,Foo值可以在域A或域B中找到(不在两者中)。在这些域中搜索的技术是完全不同的,但它们共享成功搜索往往快速返回的属性,而不成功的搜索必须遍历整个数据集,因此需要很长时间。

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

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

我对Go的并发限制的理解是否正确?还有另一种方法可以达到给定的结果吗?

2 个答案:

答案 0 :(得分:16)

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

首先,我在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-带通信。

答案 1 :(得分:5)

您可以使用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