Whenever someone works with Go’s goroutines and channels, they first try to compare them with threads in other programming languages. Concurrent programming in programming languages like C, C++ is painful as my senior colleague Chaitra. M says “Oh man! You got a new tool called Go where all the burden in concurrent programming is uplifted! Today’s kids are taking things for granted”

Coming from Python and JS background, I can only think about asynchronous programming using Twisted and NodeJS. There are no true threads in Python. On top, we have GIL(Global Interpreter Lock) which never allows me to utilize multiple cores (on a minimum two core machine). After truly empathizing with the Go’s standpoint, I am attempting to instruct Python developers to think in terms of Go’s ideology. I think Go provides very high-level constructs for doing concurrent programming. For a Python guy like me, synchronous blocking code is common. Go is not a Yet Another Programming Language, but much more than that.

I am a full stack developer and author of the book “Building RESTFul web services with Go”.

As experts always say dynamic programming languages are good for web development where CPU operations are limited. I/O can be handled well by frameworks like Django, Express JS. Complex systems like flight/movie booking, real-time collaboration editor, and payments gateways need a critical design because of a lot of variables in the processing pipeline. Go can give powers to an average python/JS developer to think beyond traditional programming. Heed me! Designing complex systems is relatively easy in Go.

Most of the tutorials out there on the Go’s channels and goroutines are rather confusing than being friendly. Here, I make an attempt to simplify the high-level constructs available in Go to do some serious tasks in few lines of code. I lay the foundation and build examples on top of that. It will be a fun ride, so stick with me.

Go’s concurrency is based on Communicating Sequential Processes(CSP). It is a formal language proposed by C.A.R Hoare. This world is full of sequential processes which can run in parallel to deal with a single complete operation. The famous example is our washing machine. For example, In a washing machine, we place our clothes in the washer. We can then remove the first set of clothes and put them in the dryer. Then, add the second set of clothes to the washer. Now both washer and dryer are running in parallel. We are not going to discuss concurrency vs parallelism here. You already got one holy grail talk by Rob Pike here. https://talks.golang.org/2012/waza.slide#1

What we are going to talk here is to understand Go’s concurrency and how the Go language is different from other dynamic languages like Python, JavaScript. By the end of this article, the concepts of Go’s concurrency will be clear to you. When someone says “Go”, simpler solutions to complex problems will run in the back of our mind. Go can unleash all your CPU cores and can execute things in parallel. It sounds faster job completion, but it depends on what problem we are solving. All the time, we deal with concurrent problems which need to execute sequentially.

Concurrency is a better way of solving a sequential problem. We can achieve concurrency through parallelism when tasks are independent and not much communication needed. When tasks are dependent(Producer/Consumer) copying data to and fro onto different CPU cores makes the program run very slow and be a performance clog.

Parallel solutions works for problems which are intrinsically parallel. Concurrent solutions are better in majority of cases.

If you have a 4 core CPU, at a given time, you can make your computer execute a maximum of 4 different instructions. Even though you have hundreds of threads, only 4 threads can be busy while others are paused. In case of a single core, only one instruction at a time. Many developers mistakes that on a single core, multiple lightweight threads can do multiple things at a given time. It is not true. The execution-wise, only one thread can occupy the CPU time. There is an exception when I/O comes into the picture. Even on a single core, at a given time, one thread can occupy CPU and others can do I/O in parallel. The example is you can write a Python program to copy the standard input to standard output(console by default) and also compute some busy algorithm at the same time. One is the I/O, other is a CPU bound operation.

We do stick to the single core for now. Why are we bothering about all those details? The intention of this article is not to show why Single-core Vs Multi-core scales. It is to show even on a single thread, how Go’s concurrency is different from thread-based concurrency in other programming languages that makes us solve problems in a clear way.

Think it like this. A postmaster does stamping on letters. A postman brings letters to the office from postbox. A sender puts a mail letter in the postbox. All three are working concurrently. If postmaster does stamp all available posts, he waits for the postman to bring few more. If postbox is empty, postman waits for more posts to be placed in the postbox. A concurrent Go solution can be easily designed for this problem compared to a traditional thread-based solution.

Threading In Python

In Python threading package enables us to perform concurrent tasks. When you need to make concurrent I/O requests, or working with the combination of CPU + I/O, you use threads. Let us write a small example showing how to calculate Fibonacci and copy the STDIN to STDOUT at the same time.

This program is creating two long-running threads:

One collects the user input and prints it back to the console Another one computes Fibonacci for random numbers

Here, I used the class syntax of the thread. We can also create a thread using an instance of threading.Thread by specifying a target function to run.

If you see, one is the CPU operation and other is an I/O operation. Both are running at the same time. The output is this.