Thursday, December 22, 2011

A simple illustration of the use of goroutines and channels in Google Go

For a long time I've been meaning to spend some quality time with Google Go and I finally have the chance. For the little home project I'm working on I needed a way to generate unique IDs. In Go there's a really nice and simple way of doing this: assign a single goroutine as an ID generator and use a channel as the way to grab a new ID.

Here's the code:
    idMaker := make(chan string)

    go func() {
        var counter int64 = 0
        for {
            idMaker <- fmt.Sprintf("%x", counter)
    } ()
The first line makes a channel that will be used to communicate strings. In this case, I'd decided to have unique string IDs.

Then there's a go function (in this case an anonymous function) that contains a 64 bit integer counter that is incremented every time an ID is generated. When an ID is generated it is formatted as a hex number and made available on the channel. It just loops around forever providing IDs and only updating the counter when an ID has been used.

Any other part of the program can grab an ID like this:
    id := <-idMaker
Because reading from a channel is atomic and only one part of the program can read from the channel at once this eliminates any headaches about threads or processes needing to share some unique ID generating code. In fact, multiple goroutines can use exactly the same channel to get unique IDs trivially.

This works because Google Go takes its channel synchronization idea from CSP where communication is how synchronization is done. There's no need for any sort of locking around the var counter because it only gets updated in one place (inside the goroutine) and it only gets updated when its value has been consumed by reading from the channel.

No comments: