4 ms·
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 p
by mitchellh 13y ago
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.
}
- latch 13y agoCan't pass up a select without showing a timeout. This was an "ah ha" moment for me and go: select { case <-myChan: // Do a thing case <- time.After(10 * time.Second): // default/error whatever }
- robflynn 13y agoThanks for posting this. I'm going to be learning Go for a little side project and couldn't quite remember this mechanism.
- jzelinskie 13y agoYou can also use time.Tickers to schedule events to occur every so often in a similar fashion. for now := range time.NewTicker(time.Minute).C { fmt.Printf("%s is the current time\n", now) } In case you are unfamiliar, the range keyword, when used on a channel, is equivalent to: for { select { case now := <-time.NewTicker(time.Minute).C: fmt.Printf("%s is the current time\n", now) } }
- zimbatm 13y agoOn the second example, wouldn't it make sense to create the ticker outside of the for loop instead ?
- jzelinskie 13y agoYep, 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
- ominous_prime 13y agoNo, it operates more like: 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.
- jbert 13y agoThat'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: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html#%_sec_3.2.3 http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html... [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.
- rwj 13y agoWith 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.
- jbert 13y agoYes, 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.