Missing Objects from Go Channels or: The coder is an idiot and used a queue like a slice…

This is probably self-evident to most sensible, educated people out there but… Golang Channels are queues and not slices!

An Idiot Writes…

So the following code looks superficially right – push the numbers 0 to 33 into a queue and then read them out with a loop, printing them to the screen as you go – except, when run, you’ll only get the numbers 0 to 16. Try it here and see.

package main

import (
	"fmt"
)

func main() {
	c := make(chan int, 100)
	for i := 0; i < 34; i++ {
		fmt.Println(i)
		c <- i
	}
	fmt.Println("===")
	fmt.Println("length")
	fmt.Println(len(c))
	fmt.Println("===")
	for i := 0; i < len(c); i++ {
		a := <-c
		fmt.Println(a)
	}
	fmt.Println("===")
}

So what’s the problem? Well, c – our Go Channel – doesn’t stay the same length after you interact with it. Why? a := <-c (the command to get the first object in the channel) alters the size of the channel as it removes the retrieved object – so a 34 object channel becomes a 33 object channel after we retrieve our first number meanwhile our counter, i, continues to count upwards until i is high enough that i < len(c) fails and the for-loop ends before the channel has properly drained.

Enlightenment…

The simple solution is to get the length of the channel once and to use that for your counter. Try it here.

package main

import (
	"fmt"
)

func main() {
	c := make(chan int, 100)
	for i := 0; i < 34; i++ {
		fmt.Println(i)
		c <- i
	}
	fmt.Println("===")
	fmt.Println("length")
	fmt.Println(len(c))
	fmt.Println("===")
	max := len(c)
	for i := 0; i < max; i++ {
		a := <-c
		fmt.Println(a)
	}
	fmt.Println("===")
}

More…

And why was I using a loop with a counter in it? Because I wanted to produce a numbered list of results and I was too lazy to read it out into a slice and then work with that. A better solution would probably involve replacing our channel reading loop definition as follows…

 for i := 0; len(c) > 0; i++

Leave a Reply

Your email address will not be published. Required fields are marked *