I recently watched Rob Pike's talk on Concurrency Patterns in Go, and was really impressed by how easy it was to make solid concurrent code without relying on threads, mutexes/locks or anything more complicated than a channel -- which I'm beginning to learn is one of the coolest things about Go, and has some incredibly elegant simplicity.
Rob Pike's talk finished with a slightly complex example of a concurrent web-search with a timeout, which I found on Github and decided to adapt slightly for myself, with some more comments and helper functions to make it super-easy to read.
I also learnt in some more detail how the select
loop works, which Rob didn't go into in much detail. It's a really cool high-level abstraction! My understanding is that it's quite like a switch/case
statement, which waits for something interesting to happen and delegates to the appropriate block of code. For example:
select {
case result := <-c:
results = append(results, result)
case <-timeout:
fmt.Println("timed out");
return
}
This code waits for a value to be pushed onto either of the channels c
or timeout
:
-
If it's
c
that's received the value, that value gets pulled out into a value calledresult
, and appended to theresults
array. -
If
timeout
has got a value, we print an error message and return straight away.
I also used a neat shortcut for "extract a value from one channel and put it onto another, like so:
result <- <- c
My understanding is that <- c
gets evaluated to a value v
first, then result <- v
has the expected behaviour of placing v
onto the channel.
What I'm enjoying about Go right now is that with regard to concurrency, the structure of a program seems incredibly intuitive to anyone familiar with the idea of queues. I'm not worrying about whether I have a certain number of threads running, or whether my mutexes are going to cause a deadlock, or whether the number of locks I've got are rendering my application essentially single-threaded -- I'm just specifying a bunch of "things to do", and Go handles multiplexing them over system threads.
That's not to say Go doesn't have mutexes and locks -- but a lot of the time, it's very likely that channels and goroutines are a more elegant (and probably more efficient) way of doing things.
Have a look at my slightly-adapted search engine example here: