mic(s)

Concurrency Bloopers

July 21, 2019

Earlier this week, I ran into a bug that I couldn’t quite understand. The code looked a bit like this

https://play.golang.org/p/29mw6PEDm2t

My task was to create a program that fetches data, processes it, and then loads the data into a database. My initial thought was, okay, let’s think about this in terms of streams. A stream of incoming data flows in through a channel - let’s call that channel, received. Some function will then read off of received and process each item in that channel, and then send the result to a stream of processed data, or to a channel called, processed. Some other function will then read off of processed and either load it to a database, or in the playground example, simply print out what was processed. Thinking in streams allowed me to decouple data structures from upstream and downstream processes.

However, when I ran the program, I thought the results were quite weird. There was no errors, no race condition, but the only channel being read was the received channel. Then the processed channel was read afterwards. Hm. That was not what I was expecting. The code that ran behaved synchronously, despite the fact that the mental model in my mind, was concurrent. I was expecting one datum to be sent to the received channel, and then consequently, in order for the received channel to send another datum, processed channel would be read.

After a couple hours of debugging, I saw one minor but enormous bug. Here is the correction, based on the example above

https://play.golang.org/p/PUx_TXX6esV

I was reading off the received channel on the same thread as reading off the processed channel. Therefore, processed could not be read until received was closed. The solution was to wrap reading off the received channel in a goroutine so that each channel can be read in its own thread/goroutine.

Concurrency is complex. Always make sure to verify if the code written reflects the mental model correctly. If you’re going to return a channel, wrap the process that sends to that channel in a goroutine.


Michelle

Written by Michelle who enjoys reading, writing software, and petting cats. Twitter Github