The talk is worth watching, but is based on a single big "trick" (but really language feature).
The key thing shown in this talk to unlock all the other cool patterns is that a nil channel blocks indefinitely in a select statement, meaning it is never selected. So you can set channels to nil in order to "turn off" certain code paths in a select. Example:
var myChan chan int
if someCondition {
// Turn on case by setting the channel
myChan = someChannel
}
select {
case <-myChan:
// Do a thing. Will never execute if myChan is nil.
// ... etc.
}
That's the main trick, but the other pattern there I really liked was the idea of pulling all mutable state into the function which was running as the goroutine (and manipulated by the for-select).
It's a lot like an object instance, responding to messages, changing internal state and emitting messages.
In fact, here is the same approach in SICP, where they start to model objects as messages passed to a closure with internal mutable state:
[scroll down a bit for exercise 3.11, the "cond dispatch" is analagous to the "for-select" case dispatch, except of course that golang select handles concurrency.]
It's the old "objects are a poor man's closures"/"closures are a poor man's object" duality.
With this approach, you could pull a lot of state out of the structure, and move it into variables local to the goroutine. It is interesting how this approach moves Go a lot closer to Erlang-style actors.
Yes, it seems very close to actors but I guess that's not too surprising if you're trying to converge on "ways to do concurrency which don't suck" from different languages.
ticker := time.NewTicker(time.Minute)
for {
now, ok := <-ticker.C
if !ok {
break
}
fmt.Printf("%s is the current time\n", now)
}
Your two loops are superficially equivalent only because the ticker isn't going to close its channel. Plus, you're creating a new ticker on every iteration in your second example, and you don't need the select statement, because your only blocking on a single receive operation.
The range over a channel is especially useful for a channel that will be closed, so you can break from the loop.
Yep, that was my bad. I got distracted when writing the example and didn't think things through because I realized I had installed Go 1.1 for i386 on my laptop and not x86_64. Such is life when commenting at 6AM :P
Exactly what I've been looking for. The original presentation Pike gave was great as an intro, but I was looking for some more applications. Definitely looking forward to more material like this.
Also, I love the tongue-in-cheek reference to what I presume is Google Reader:
Example: feed reader
My favorite feed reader disappeared. I need a new one.
Why not write one?
Where do we start?
Really interesting. Could someone explain how these features relate in a language like python or C? Do they have the same features, but are more complicated to implement or is the architecture not even there to support such?
Neither language has channels or selects baked in.
Python does have threadsafe queues in the standard library, which you can use to coordinate work between threads and processes.
C doesn't come with anything like this, but you can use a library like ZeroMQ. The main Go compilers are written in C, so clearly anything Go can do C can do too -- but it'll be more work.
The key thing shown in this talk to unlock all the other cool patterns is that a nil channel blocks indefinitely in a select statement, meaning it is never selected. So you can set channels to nil in order to "turn off" certain code paths in a select. Example: