Buffered Channels in Golang

A few weeks ago when I was reading The Go Programming Language I was reading about buffered channels and had a gut instinct that I could write some code taking advantage of them in a precise way. This was the comical code that came out of it.

In Go a channel is typically used to pass messages from one goroutine to another, but a channel can be used to pass data in other situations too; it’s just more expensive to use a channel than, say, a function call. A channel blocks once it’s either full (for writing) or empty (for reading.) So when a channel has a single slot (an unbuffered channel) things that use channels work in lockstep and are synchronized.

A buffered channel has more than one slot, but once the channel is full or empty it works the same. Really all the buffering does is give you a little slack. When I read this I thought for a couple minutes about what ridiculous code I could write using a buffered channel. Here’s what I came up with:

package main

import "fmt"

func main() {
	c := make(chan int, 2)
	c <- 1
	c <- 0

	for {
		n := <-c
		fmt.Println(n)
		c <- n + <-c
		c <- n
	}
}

It’s the Fibonacci sequence using the iterative solution, but instead of two variables or an array, this uses a channel as a kind of ring buffer. It’s ridiculous and stupid, but it was fun and it works.

Comically, to me, it’s so fast that it exhausts the integer type almost immediately, thus printing negative numbers and other nonsense. Here’s the bigint version:

package main

import "fmt"
import "math/big"

func main() {
	c := make(chan *big.Int, 2)
	c <- big.NewInt(1)
	c <- big.NewInt(0)

	for {
		n := <-c
		fmt.Println(n)
		c <- big.NewInt(0).Add(n, <-c)
		c <- n
	}
}

As I’ve mentioned before, to learn more about Go, I strongly recommend The Go Programming Language. It’s one of the best language oriented programming books I’ve ever read, and one of the best on it’s own. I suggest reading it even if you already know Go in and out.

Posted Mon, May 14, 2018

Receive Blog Posts in Your Email