3

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

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

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

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

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

4

2 回答 2

16

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

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

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

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    }

此外,虽然从通道接收通常会阻塞,但您也可以从通道进行非阻塞接收

如果在表单的赋值或初始化中使用了接收表达式

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

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

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

于 2009-11-15T18:10:30.377 回答
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");
}

参考

于 2009-11-15T18:10:03.187 回答