views:

156

answers:

2

I've only just recently learned about Google's programming language, Go. I've been intrigued by its offered support for concurrency, and set out to learn more about it. However, I went looking to see how Go implemented a particular feature of concurrency, and so far I haven't seen any evidence at all that this feature is there at all.

Here's a hypothetical situation: suppose we are programming a function to determine the Foo value of a particular input. For any given input, the Foo value is found either in domain A, or domain B (not in both). The techniques of searching in these domains are quite different, but they share the property that successful searches tend to return quickly, while unsuccessful searches must go through the entire dataset to be exhaustive and therefore take a long time.

Now, in other languages that employ concurrency (such as Cilk) one could program the function Foosearch so that it spawned an Asearch function and a Bsearch function. These functions would run concurrently, and whenever either of them came up with an answer, that answer would be reported to the calling function Foosearch, which would terminate any functions it had spawned that had not returned.

With Go's goroutines, however, it looks like you can only connect two routines with a channel - so you couldn't set up a channel to which either Asearch or Bsearch could send, depending on which found an answer first, and have Foosearch read from it. It also looks like you can't read from a channel without blocking on it - so you couldn't have Foosearch start Asearch and Bsearch and set up channels from both, then run in a loop checking to see if one or the other has produced an answer.

Is my understanding of the limits of Go's concurrency correct? Is there another way to achieve the given result?

+5  A: 

You can use the select keyword to receive from multiple channels.

The value will be taken from the channel that has the result earlier than the others.

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

yuku
+15  A: 

No, I don't believe your understanding of the limits of Go is correct.

For one thing, there's nothing I've seen in Go that limits channels to communicating between two routines. You can pass the same channel to both Asearch and Bsearch, and then whichever one finishes can send the result on that channel.

If instead you wanted to use two channels, and wait for one of them to get the result, you could just use the select statement. From the Go tutorial, an example selecting on a channel used to send requests, and one used to signal the server to quit:

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    }

Furthermore, while receives from a channel normally block, you can also do a non-blocking receive from a channel.

If a receive expression is used in an assignment or initialization of the form

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

the receive operation becomes non-blocking. If the operation can proceed, the boolean variable ok will be set to true and the value stored in x; otherwise ok is set to false and x is set to the zero value for its type (§The zero value).

So, there are several ways to wait for the result from multiple goroutines without blocking. I think I'd go with multiple channels multiplexed using select, as that way you can easily tell which routine returned the result without having to package that information into the value you're sending or doing some other form of out-of-band communication.

Brian Campbell